diff -ur --new-file old/atm/BUGS new/atm/BUGS --- old/atm/BUGS Tue Aug 4 20:41:05 1998 +++ new/atm/BUGS Tue Aug 11 17:01:12 1998 @@ -1,8 +1,9 @@ -Known bugs and restrictions in version 0.39 +Known bugs and restrictions in version 0.40 =========================================== - libresolve conflicts with libc on some systems - ENI driver loses synchronization on some systems, leading to panics or hung VCs (these may be two distinct problems) - few if any drivers build properly as modules - - LANE and signaling may conspire to crash the system + - MPOA may fail on RedHat 5.x with "mpcd: changed_fds = ...", due to what + seems to be a bug in RedHat's glibc diff -ur --new-file old/atm/CHANGES new/atm/CHANGES --- old/atm/CHANGES Tue Aug 4 20:48:14 1998 +++ new/atm/CHANGES Thu Aug 13 13:38:10 1998 @@ -1,3 +1,35 @@ +Version 0.39 to 0.40 (13-AUG-1998) +==================== + +Bug fixes +--------- + + - ilmid defined the value of "invalid" as 0 instead of 2 (fix by Timo + Parnanen) + - bash-2 doesn't like for n in $(SUBDIR); ... if SUBDIR is undefined (fix + by Heikki Vatiainen) + - LANE still cleared ATM_VF_RELEASED instead of calling atm_async_release_vcc, + which apparently led to stray kernel crashes in signaling (found with a lot + of help from John McPherson) + - ATM qdisc now properly re-allocates skb memory to grow headers, if necessary + - atm/switch/Makefile didn't build SUBDIRS + +New features +------------ + + - MPOA (Multi-Protocol Over ATM) client support written by Heikki Vatiainen + and Sampo Saaristo + - LANE client (zeppelin) now also supports LANE2 (by Heikki Vatiainen) + +Other changes +------------- + + - accept() now also returns on ATM_VF_CLOSE + - ATM qdisc now uses the same data format on rtnetlink as other qdiscs; new + option for user-provided headers + - atm/switch can now use "external" routing (e.g. provided by the fab control) + + Version 0.38 to 0.39 (4-AUG-1998) ==================== diff -ur --new-file old/atm/COPYING new/atm/COPYING --- old/atm/COPYING Tue Feb 17 17:13:16 1998 +++ new/atm/COPYING Wed Aug 12 17:49:12 1998 @@ -27,9 +27,14 @@ and the University of British Columbia See asn1/*.[ch] for copying terms. -The LAN Emulation client code is Copyright by Tampere University of -Technology - Telecommunications Laboratory. In addition to that, -portions of the LAN Emulation client code are Copyright (C) 1995 by -Digital Equipment Corporation. +The LAN Emulation code is Copyright by Tampere University of Technology +- Telecommunications Laboratory. In addition to that, portions of the +LAN Emulation client code are Copyright (C) 1995 by Digital Equipment +Corporation. See lane/COPYRIGHT.TUT, led/COPYRIGHT.TUT, and led/COPYRIGHT.DEC for copying terms. + +The Multi-Protocol Over ATM (MOPA) code was developed at Tampere +University of Technology - Telecommunications Laboratory and is +Copyright by Heikki Vatiainen and Sampo Saaristo. It is released under +the GNU General Public License. See the file COPYING.GPL for details. diff -ur --new-file old/atm/Makefile new/atm/Makefile --- old/atm/Makefile Tue Aug 4 12:17:42 1998 +++ new/atm/Makefile Tue Aug 11 17:42:11 1998 @@ -2,8 +2,8 @@ # "lib" must appear before anything else # "maint" must appear after "qgen" -DIRS=lib test debug qgen saal sigd maint arpd ilmid aqd man led lane switch - # tcd extra +DIRS=lib test debug qgen saal sigd maint arpd ilmid aqd man led lane mpoad \ + switch # tcd extra all: for n in $(DIRS); do $(MAKE) -C $$n || exit; done diff -ur --new-file old/atm/README new/atm/README --- old/atm/README Tue Aug 4 20:43:44 1998 +++ new/atm/README Tue Aug 11 19:43:30 1998 @@ -1,4 +1,4 @@ -ATM on Linux, release 0.39 (alpha) by Werner Almesberger, EPFL ICA +ATM on Linux, release 0.40 (alpha) by Werner Almesberger, EPFL ICA ============================================== Werner.Almesberger@epfl.ch This is experimental software. There are known major bugs and certainly diff -ur --new-file old/atm/Rules.make new/atm/Rules.make --- old/atm/Rules.make Tue Aug 4 19:40:01 1998 +++ new/atm/Rules.make Wed Aug 12 20:35:04 1998 @@ -97,7 +97,11 @@ all: [ ! -r .checker ] || $(MAKE) clean $(MAKE) do_all - for n in $(SUBDIRS); do make -C $$n || exit; done + for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n || exit; done + +# Note: bash-2 barfs on for n in ; do ... so we need this hack to sneak at +# least one item on the list. do_all: $(BOOTPGMS) $(SYSPGMS) $(USRPGMS) $(PGMS) @@ -106,7 +110,8 @@ checker: [ -r .checker ] || $(MAKE) clean $(MAKE) do_checker - @for n in $(SUBDIRS); do make -C $$n checker || exit; done + @for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n checker || exit; done do_checker: CC=checkergcc $(MAKE) -e do_all @@ -119,7 +124,8 @@ optprocess() { [ -z "$$3" -o -r "$$2/$$3" ] || \ process $$*; }; \ $(PROCLIST) - @for n in $(SUBDIRS); do make -C $$n install || exit; done + @for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n install || exit; done # optprocess is only defined for a single file. Right now we're using it only # for stdint.h @@ -130,7 +136,8 @@ install -d $$2 || exit 1; fi; }; \ optprocess() { :; }; \ $(PROCLIST) - @for n in $(SUBDIRS); do make -C $$n instdirs || exit; done + @for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n instdirs || exit; done uninstall: @process() { if [ ! -z "$$3" ]; then dir=$$2; shift 2; \ @@ -138,28 +145,33 @@ cd $$dir; rm -f $$*; fi; }; \ optprocess() { :; }; \ $(PROCLIST) - @for n in $(SUBDIRS); do make -C $$n uninstall || exit; done + @for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n uninstall || exit; done filenames: @process() { if [ ! -z "$$3" ]; then dir=$$2; shift 2; \ for n in $$*; do echo $$dir/$$n; done; fi; }; \ optprocess() { process $$*; }; \ $(PROCLIST) - @for n in $(SUBDIRS); do make -C $$n filenames || exit; done + @for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n filenames || exit; done depend: $(CPP) -M *.c $(INCLUDES) -I$(TOPDIR)/lib >.tmpdepend mv .tmpdepend .depend - for n in $(SUBDIRS); do make -C $$n depend || exit; done + for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n depend || exit; done clean: rm -f *.o core .checker y.tab.h y.tab.c lex.yy.c $(TRASH) - for n in $(SUBDIRS); do make -C $$n clean || exit; done + for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n clean || exit; done spotless: clean rm -f $(BOOTPGMS) $(SYSPGMS) $(USRPGMS) $(PGMS) *.a rm -f .depend .checker - for n in $(SUBDIRS); do make -C $$n spotless || exit; done + for n in "" $(SUBDIRS); do [ -z "$$n" ] || \ + make -C $$n spotless || exit; done lex.yy.o: lex.yy.c y.tab.h $(CC) -c $(CFLAGS_LEX) lex.yy.c diff -ur --new-file old/atm/USAGE new/atm/USAGE --- old/atm/USAGE Tue Aug 4 21:15:42 1998 +++ new/atm/USAGE Thu Aug 13 13:38:23 1998 @@ -1,4 +1,4 @@ -Usage instructions - ATM on Linux, release 0.39 +Usage instructions - ATM on Linux, release 0.40 ------------------------------------------------- For updates of ATM on Linux, please check the Web page at @@ -17,7 +17,7 @@ In order to install this package, you need - the package itself - ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.39.tar.gz + ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.40.tar.gz - the Linux kernel, version 2.1.105, e.g. from ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.1.105.tar.gz - Perl, version 4 or 5 @@ -33,7 +33,7 @@ all the files listed above there. Then extract the ATM on Linux distribution: -tar xfz atm-0.39.tar.gz +tar xfz atm-0.40.tar.gz and the kernel source: @@ -57,8 +57,9 @@ atm/test/ Test programs: align, aping, aread, awrite, br, bw, isp, ttcp_atm, window atm/arpd/ ATMARP tools and demon: atmarp, atmarpd - atm/led/ LAN Emulation demon: led + atm/led/ LAN Emulation demon: zeppelin atm/lane/ LAN Emulation servers: bus, lecs, les + atm/mpoad/ Multi-Protocol Over ATM demon: mpcd atm/aqd/ Arequipa demon: aqpvc, arequipad atm/debug/ Debugging tools: aqtest, delay, ed, encopy, endump, svctor, zndump, and znth diff -ur --new-file old/atm/VERSION new/atm/VERSION --- old/atm/VERSION Tue Aug 4 20:31:03 1998 +++ new/atm/VERSION Wed Aug 12 19:42:23 1998 @@ -1 +1 @@ -0.39 +0.40 diff -ur --new-file old/atm/arpd/arp.c new/atm/arpd/arp.c --- old/atm/arpd/arp.c Tue Jul 28 16:14:18 1998 +++ new/atm/arpd/arp.c Tue Aug 11 16:09:36 1998 @@ -166,6 +166,7 @@ unsigned char *num_tl,unsigned char *sub_tl) { if (!addr) return; + if (addr->sas_family != AF_ATMSVC) return; if (!*addr->sas_addr.pub) *sub_tl = 0; else { *num_tl = strlen(addr->sas_addr.pub) | TL_E164; diff -ur --new-file old/atm/atm.patch new/atm/atm.patch --- old/atm/atm.patch Tue Aug 4 21:15:30 1998 +++ new/atm/atm.patch Thu Aug 13 13:37:20 1998 @@ -2753,7 +2753,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/eni.h Tue Aug 4 17:54:42 1998 ++++ work/drivers/atm/eni.h Tue Aug 11 19:45:45 1998 @@ -0,0 +1,114 @@ +/* drivers/atm/eni.h - Efficient Networks ENI155P device driver declarations */ + @@ -3451,7 +3451,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/suni.h Tue Aug 4 17:54:40 1998 ++++ work/drivers/atm/suni.h Tue Aug 11 19:45:41 1998 @@ -0,0 +1,210 @@ +/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */ + @@ -6190,7 +6190,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/zatm.h Tue Aug 4 17:54:46 1998 ++++ work/drivers/atm/zatm.h Tue Aug 11 19:45:52 1998 @@ -0,0 +1,136 @@ +/* drivers/atm/zatm.h - ZeitNet ZN122x device driver declarations */ + @@ -6386,7 +6386,7 @@ #ifdef CONFIG_VT console_map_init(); --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/arequipa.h Tue Aug 4 17:58:20 1998 ++++ work/include/linux/arequipa.h Tue Aug 11 19:46:26 1998 @@ -0,0 +1,63 @@ +/* arequipa.h - Arequipa interface definitions */ + @@ -6452,7 +6452,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm.h Tue Aug 4 16:52:29 1998 ++++ work/include/linux/atm.h Tue Aug 11 19:45:40 1998 @@ -0,0 +1,234 @@ +/* atm.h - general ATM declarations */ + @@ -6689,7 +6689,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm_eni.h Tue Jun 9 21:32:11 1998 ++++ work/include/linux/atm_eni.h Tue Aug 11 19:45:45 1998 @@ -0,0 +1,15 @@ +/* atm_eni.h - Driver-specific declarations of the ENI driver (for use by + driver-specific utilities) */ @@ -6774,7 +6774,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm_zatm.h Tue Jun 9 21:32:11 1998 ++++ work/include/linux/atm_zatm.h Tue Aug 11 19:45:52 1998 @@ -0,0 +1,54 @@ +/* atm_zatm.h - Driver-specific declarations of the ZATM driver (for use by + driver-specific utilities) */ @@ -6831,7 +6831,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmarp.h Tue Jun 9 21:32:11 1998 ++++ work/include/linux/atmarp.h Tue Aug 11 19:46:16 1998 @@ -0,0 +1,42 @@ +/* atmarp.h - ATM ARP protocol and kernel-demon interface definitions */ + @@ -6876,7 +6876,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmclip.h Fri Jul 17 22:26:52 1998 ++++ work/include/linux/atmclip.h Tue Aug 11 19:46:26 1998 @@ -0,0 +1,26 @@ +/* atmclip.h - Classical IP over ATM */ + @@ -6905,7 +6905,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmdev.h Tue Aug 4 17:54:24 1998 ++++ work/include/linux/atmdev.h Tue Aug 11 19:45:41 1998 @@ -0,0 +1,309 @@ +/* atmdev.h - ATM device driver declarations */ + @@ -7217,11 +7217,11 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmioc.h Tue Jun 9 21:32:11 1998 -@@ -0,0 +1,38 @@ ++++ work/include/linux/atmioc.h Tue Aug 11 19:17:07 1998 +@@ -0,0 +1,39 @@ +/* atmioc.h - ranges for ATM-related ioctl numbers */ + -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ ++/* Written 1995-1998 by Werner Almesberger, EPFL LRC */ + + +/* @@ -7251,6 +7251,7 @@ +/* 0x90-0xbf: Reserved for future use */ +#define ATMIOC_AREQUIPA 0xc0 /* Application requested IP over ATM, glob. u. */ +#define ATMIOC_LANE 0xd0 /* LAN Emulation, globally unique */ ++#define ATMIOC_MPOA 0xd8 /* MPOA, globally unique */ +#define ATMIOC_CLIP 0xe0 /* Classical IP over ATM control, globally u. */ +#define ATMIOC_CLIP_END 0xef +#define ATMIOC_SPECIAL 0xf0 /* Special-purpose controls, globally unique */ @@ -7258,8 +7259,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmlec.h Tue Aug 4 17:58:20 1998 -@@ -0,0 +1,65 @@ ++++ work/include/linux/atmlec.h Tue Aug 11 19:46:26 1998 +@@ -0,0 +1,70 @@ +/* + * + * ATM Lan Emulation Daemon vs. driver interface @@ -7287,11 +7288,13 @@ + l_svc_setup, + l_addr_delete, l_topology_change, + l_flush_complete, l_arp_update, ++ l_narp_req, /* LANE2 mandates the use of this */ + l_config, l_flush_tran_id, -+ l_set_lecid, l_arp_xmt ++ l_set_lecid, l_arp_xmt, ++ l_associate_req +} atmlec_msg_type; + -+#define ATMLEC_MSG_TYPE_MAX l_arp_xmt ++#define ATMLEC_MSG_TYPE_MAX l_associate_req + +struct atmlec_config_msg { + unsigned int maximum_unknown_frame_count; @@ -7302,6 +7305,7 @@ + unsigned long arp_response_time; + unsigned long flush_timeout; + unsigned long path_switching_delay; ++ unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */ +}; + +struct atmlec_msg { @@ -7314,6 +7318,8 @@ + unsigned long flag;/* Topology_change flag, + remoteflag, permanent flag, + lecid, transaction id */ ++ unsigned int targetless_le_arp; /* LANE2 */ ++ unsigned int no_source_le_narp; /* LANE2 */ + } normal; + struct atmlec_config_msg config; + } content; @@ -7322,10 +7328,111 @@ +struct atmlec_ioc { + int dev_num; + unsigned char atm_addr[ATM_ESA_LEN]; -+ unsigned char receive; /* 1= receive vcc, 0 = send_vcc */ ++ unsigned char receive; /* 1= receive vcc, 0 = send vcc */ +}; +#endif /* _ATMLEC_H_ */ --- /dev/null Tue Jan 1 05:00:00 1980 ++++ work/include/linux/atmmpc.h Tue Aug 11 19:18:07 1998 +@@ -0,0 +1,98 @@ ++#ifndef _ATMMPC_H_ ++#define _ATMMPC_H_ ++ ++#include ++#include ++ ++#define ATMMPC_CTRL _IO('a', ATMIOC_MPOA) ++#define ATMMPC_DATA _IO('a', ATMIOC_MPOA+1) ++ ++#define MPC_SOCKET_INGRESS 1 ++#define MPC_SOCKET_EGRESS 2 ++ ++struct atmmpc_ioc { ++ int dev_num; ++ uint32_t ipaddr; /* the IP address of the shortcut */ ++ int type; /* ingress or egress */ ++}; ++ ++typedef struct in_ctrl_info { ++ uint8_t Last_NHRP_CIE_code; ++ uint8_t Last_Q2931_cause_value; ++ uint8_t eg_MPC_ATM_addr[ATM_ESA_LEN]; ++ uint32_t tag; ++ uint32_t in_dst_ip; /* IP address this ingress MPC sends packets to */ ++ uint32_t service_category; ++ uint16_t holding_time; ++ uint32_t request_id; ++} in_ctrl_info; ++ ++typedef struct eg_ctrl_info { ++ uint8_t DLL_header[256]; ++ uint8_t DH_length; ++ uint32_t cache_id; ++ uint32_t tag; ++ uint32_t mps_ip; ++ uint32_t eg_dst_ip; /* IP address to which ingress MPC sends packets */ ++ uint8_t in_MPC_data_ATM_addr[ATM_ESA_LEN]; ++ uint16_t holding_time; ++} eg_ctrl_info; ++ ++struct k_message{ ++ uint16_t type; ++ uint8_t MPS_ctrl[ATM_ESA_LEN]; ++ union { ++ in_ctrl_info in_info; ++ eg_ctrl_info eg_info; ++ } content; ++} k_message; ++ ++struct llc_snap_hdr { /* RFC 1483 LLC/SNAP encapsulation for routed IP PDUs */ ++ uint8_t dsap; /* Destination Service Access Point (0xAA) */ ++ uint8_t ssap; /* Source Service Access Point (0xAA) */ ++ uint8_t ui; /* Unnumbered Information (0x03) */ ++ uint8_t org[3]; /* Organizational identification (0x000000) */ ++ uint8_t type[2]; /* Ether type (for IP) (0x0800) */ ++}; ++ ++/* MPC parameter defaults */ ++ ++#define MPC_P1 10 /* Shortcut-Setup Frame Count */ ++#define MPC_P2 1 /* Shortcut-Setup Frame Time */ ++#define MPC_P3 0 /* Flow-detection Protocols */ ++#define MPC_P4 5 /* MPC Initial Retry Time */ ++#define MPC_P5 40 /* MPC Retry Time Maximum */ ++#define MPC_P6 160 /* Hold Down Time */ ++#define HOLDING_TIME_DEFAULT 1200 /* same as MPS-p7 */ ++ ++/* MPC constants */ ++ ++#define MPC_C1 2 /* Retry Time Multiplier */ ++#define MPC_C2 60 /* Initial Keep-Alive Lifetime */ ++ ++/* Message types - to MPOA daemon */ ++ ++#define SND_MPOA_RES_RQST 201 ++#define SET_MPS_CTRL_ADDR 202 ++#define SND_MPOA_RES_RTRY 203 /* Different type in a retry due to req id.*/ ++#define STOP_KEEP_ALIVE_SM 204 ++#define EGRESS_ENTRY_REMOVED 205 ++#define SND_EGRESS_PURGE 206 ++#define DIE 207 ++#define DATA_PLANE_PURGE 208 /* Data plane purge because of egress cache hit miss or dead MPS */ ++#define OPEN_INGRESS_SVC 209 ++ ++/* Message types - from MPOA daemon */ ++ ++#define MPOA_TRIGGER_RCVD 101 ++#define MPOA_RES_REPLY_RCVD 102 ++#define INGRESS_PURGE_RCVD 103 ++#define EGRESS_PURGE_RCVD 104 ++#define MPS_DEATH 105 ++#define CACHE_IMPOS_RCVD 106 ++#define SET_MPC_CTRL_ADDR 107 /* Our MPC's control ATM address */ ++#define SET_MPS_MAC_ADDR 108 ++#define CLEAN_UP_AND_EXIT 109 ++ ++#endif /* _ATMMPC_H_ */ ++ +--- /dev/null Tue Jan 1 05:00:00 1980 +++ work/include/linux/atmsap.h Tue Jun 9 21:32:11 1998 @@ -0,0 +1,161 @@ +/* atmsap.h - ATM Service Access Point addressing definitions */ @@ -7490,7 +7597,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmsvc.h Tue Aug 4 17:58:20 1998 ++++ work/include/linux/atmsvc.h Tue Aug 11 19:46:26 1998 @@ -0,0 +1,52 @@ +/* atmsvc.h - ATM signaling kernel-demon interface definitions */ + @@ -7643,7 +7750,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/net/atmclip.h Tue Aug 4 17:58:12 1998 ++++ work/include/net/atmclip.h Tue Aug 11 19:46:16 1998 @@ -0,0 +1,62 @@ +/* net/atm/atmarp.h - RFC1577 ATM ARP */ + @@ -7708,8 +7815,8 @@ + +#endif --- ref/net/Config.in Tue Apr 28 20:10:10 1998 -+++ work/net/Config.in Tue Jun 9 21:32:12 1998 -@@ -23,6 +23,20 @@ ++++ work/net/Config.in Tue Aug 11 19:04:05 1998 +@@ -23,6 +23,23 @@ fi fi fi @@ -7725,13 +7832,16 @@ +# bool ' Application REQUested IP over ATM' CONFIG_AREQUIPA y + fi + tristate ' LAN Emulation (LANE) support' CONFIG_ATM_LANE y ++ if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then ++ tristate ' Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA y ++ fi + fi +fi comment ' ' tristate 'The IPX protocol' CONFIG_IPX --- ref/net/Makefile Sun Nov 30 23:00:39 1997 -+++ work/net/Makefile Tue Jun 9 21:32:12 1998 ++++ work/net/Makefile Tue Aug 11 19:03:31 1998 @@ -9,7 +9,8 @@ MOD_SUB_DIRS := ipv4 @@ -7742,7 +7852,7 @@ SUB_DIRS := core ethernet sched MOD_LIST_NAME := NET_MISC_MODULES -@@ -130,6 +131,13 @@ +@@ -130,6 +131,16 @@ ifeq ($(CONFIG_SUNRPC),m) MOD_SUB_DIRS += sunrpc endif @@ -7753,6 +7863,9 @@ +ifeq ($(CONFIG_ATM_LANE),m) + MOD_SUB_DIRS += atm +endif ++ifeq ($(CONFIG_ATM_MPOA),m) ++ MOD_SUB_DIRS += atm ++endif endif ifeq ($(CONFIG_DECNET),y) @@ -8379,8 +8492,8 @@ +} +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/Makefile Tue Jun 9 21:32:12 1998 -@@ -0,0 +1,52 @@ ++++ work/net/atm/Makefile Tue Aug 11 20:43:58 1998 +@@ -0,0 +1,64 @@ +# +# Makefile for the ATM Protocol Families. +# @@ -8418,21 +8531,33 @@ +O_OBJS += $(NEED_IPCOM) + +ifeq ($(CONFIG_PROC_FS),y) -+O_OBJS += proc.o ++OX_OBJS += proc.o +endif + +ifeq ($(CONFIG_ATM_LANE),y) -+O_OBJS += lec.o ++O_OBJS += lec.o lane_mpoa_init.o +else + ifeq ($(CONFIG_ATM_LANE),m) ++ O_OBJS += lane_mpoa_init.o + M_OBJS += lec.o + endif +endif + ++ifeq ($(CONFIG_ATM_MPOA),y) ++O_OBJS += mpc.o mpoa_caches.o mpoa_proc.o ++else ++ ifeq ($(CONFIG_ATM_MPOA),m) ++ M_OBJS += mpoa.o ++ endif ++endif ++ +endif + + +include $(TOPDIR)/Rules.make ++ ++mpoa.o: mpc.o mpoa_caches.o mpoa_proc.o ++ ld -r -o mpoa.o mpc.o mpoa_caches.o mpoa_proc.o --- /dev/null Tue Jan 1 05:00:00 1980 +++ work/net/atm/addr.c Tue Jun 9 21:32:12 1998 @@ -0,0 +1,159 @@ @@ -8596,7 +8721,7 @@ + return total; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/addr.h Tue Aug 4 17:58:20 1998 ++++ work/net/atm/addr.h Tue Aug 11 19:46:26 1998 @@ -0,0 +1,18 @@ +/* net/atm/addr.h - Local ATM address registry */ + @@ -9284,8 +9409,8 @@ + return 0; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/common.c Tue Aug 4 18:15:09 1998 -@@ -0,0 +1,909 @@ ++++ work/net/atm/common.c Tue Aug 11 19:11:54 1998 +@@ -0,0 +1,908 @@ +/* net/atm/common.c - ATM sockets (common part for PVC and SVC) */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -9324,6 +9449,22 @@ +#include +#include "lec.h" +#include "lec_arpc.h" ++struct atm_lane_ops atm_lane_ops; ++#endif ++#ifdef CONFIG_ATM_LANE_MODULE ++EXPORT_SYMBOL(atm_lane_ops); ++#endif ++ ++#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) ++#include ++#include "mpc.h" ++struct atm_mpoa_ops atm_mpoa_ops; ++#endif ++#ifdef CONFIG_ATM_MPOA_MODULE ++EXPORT_SYMBOL(atm_mpoa_ops); ++#ifndef CONFIG_ATM_LANE_MODULE ++EXPORT_SYMBOL(atm_lane_ops); ++#endif +#endif + +#ifdef CONFIG_ATM_TCP @@ -9345,40 +9486,6 @@ +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) -+ -+#endif -+/* -+ * The attach functions are used in common.c::atm_ioctl(), -+ * ptr_to_get_dev_lec is used in proc.c::atm_info(). -+ * The functions are defined in lec.c. -+ * When lec module initializes itself it calls atm_lane_setup -+ * in lec.c::init_module(). -+ */ -+#ifdef CONFIG_ATM_LANE -+static int (*ptr_to_lecd_attach)(struct atm_vcc *vcc, int arg) = lecd_attach; -+static int (*ptr_to_lec_mcast_attach)(struct atm_vcc *vcc, int arg) = lec_mcast_attach; -+static int (*ptr_to_lec_vcc_attach)(struct atm_vcc *vcc, void *arg) = lec_vcc_attach; -+struct device **(*ptr_to_get_dev_lec)(void) = get_dev_lec; -+#endif -+ -+#ifdef CONFIG_ATM_LANE_MODULE -+static int (*ptr_to_lecd_attach)(struct atm_vcc *vcc, int arg) = NULL; -+static int (*ptr_to_lec_mcast_attach)(struct atm_vcc *vcc, int arg) = NULL; -+static int (*ptr_to_lec_vcc_attach)(struct atm_vcc *vcc, void *arg) = NULL; -+struct device **(*ptr_to_get_dev_lec)(void) = NULL; -+ -+void atm_lane_setup (int (*attach)(struct atm_vcc *vcc, int arg), -+ int (*mcast)(struct atm_vcc *vcc, int arg), -+ int (*vcc)(struct atm_vcc *vcc, void *arg), -+ struct device **(*dev_lec_ptr)(void)) { -+ ptr_to_lecd_attach = attach; -+ ptr_to_lec_mcast_attach = mcast; -+ ptr_to_lec_vcc_attach = vcc; -+ ptr_to_get_dev_lec = dev_lec_ptr; -+ -+} -+ -+EXPORT_SYMBOL(atm_lane_setup); +#endif + + @@ -9479,6 +9586,9 @@ +} + + ++EXPORT_SYMBOL(atm_async_release_vcc); ++ ++ +static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) +{ + int max_sdu; @@ -9937,19 +10047,33 @@ +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + case ATMLEC_CTRL: + if (!suser()) return -EPERM; -+ if (ptr_to_lecd_attach == NULL) { -+ printk ("no lec, try insmod lec first\n"); -+ return -ENOSYS; -+ } -+ error = ptr_to_lecd_attach(vcc, (int)arg); ++ if (atm_lane_ops.lecd_attach == NULL) ++ atm_lane_init(); ++ if (atm_lane_ops.lecd_attach == NULL) /* try again */ ++ return -ENOSYS; ++ error = atm_lane_ops.lecd_attach(vcc, (int)arg); + if (error >= 0) sock->state = SS_CONNECTED; + return error; + case ATMLEC_MCAST: + if (!suser()) return -EPERM; -+ return ptr_to_lec_mcast_attach(vcc, (int)arg); ++ return atm_lane_ops.mcast_attach(vcc, (int)arg); + case ATMLEC_DATA: + if (!suser()) return -EPERM; -+ return ptr_to_lec_vcc_attach(vcc, (void*)arg); ++ return atm_lane_ops.vcc_attach(vcc, (void*)arg); ++#endif ++#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) ++ case ATMMPC_CTRL: ++ if (!suser()) return -EPERM; ++ if (atm_mpoa_ops.mpoad_attach == NULL) ++ atm_mpoa_init(); ++ if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */ ++ return -ENOSYS; ++ error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg); ++ if (error >= 0) sock->state = SS_CONNECTED; ++ return error; ++ case ATMMPC_DATA: ++ if (!suser()) return -EPERM; ++ return atm_mpoa_ops.vcc_attach(vcc, arg); +#endif +#ifdef CONFIG_ATM_TCP + case SIOCSIFATMTCP: @@ -10300,7 +10424,7 @@ + skb_queue_head_init(from); +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/ipcommon.h Tue Aug 4 17:58:35 1998 ++++ work/net/atm/ipcommon.h Tue Aug 11 19:54:47 1998 @@ -0,0 +1,22 @@ +/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ + @@ -10510,8 +10634,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/lec.c Tue Aug 4 20:41:09 1998 -@@ -0,0 +1,1896 @@ ++++ work/net/atm/lec.c Tue Aug 11 19:12:33 1998 +@@ -0,0 +1,1976 @@ +/* + * lec.c: Lan Emulation driver + * Marko Kiiskila carnil@cs.tut.fi @@ -10544,8 +10668,7 @@ +#include "lec.h" +#include "lec_arpc.h" +#include "tunable.h" -+#include "resources.h" -+ ++#include "resources.h" /* for bind_vcc() */ + +#define DPRINTK(format,args...) +/* @@ -10563,11 +10686,21 @@ +static int lec_init(struct device *dev); +static __inline__ struct lec_arp_table* lec_arp_find(struct lec_priv *priv, + unsigned char *mac_addr); ++static __inline__ int lec_arp_remove(struct lec_arp_table **lec_arp_tables, ++ struct lec_arp_table *to_remove); +/* LANE2 functions */ -+void lane2_associate_ind (struct lec_priv *priv, u8 *mac_address, ++static void lane2_associate_ind (struct device *dev, u8 *mac_address, + u8 *tlvs, u32 sizeoftlvs); -+int lane2_resolve(u8 *dst_mac, int force, struct device *dev, ++static int lane2_resolve(struct device *dev, u8 *dst_mac, int force, + u8 **tlvs, u32 *sizeoftlvs); ++static int lane2_associate_req (struct device *dev, u8 *lan_dst, ++ u8 *tlvs, u32 sizeoftlvs); ++ ++static struct lane2_ops lane2_ops = { ++ lane2_resolve, /* resolve, spec 3.1.3 */ ++ lane2_associate_req, /* associate_req, spec 3.1.4 */ ++ NULL /* associate indicator, spec 3.1.5 */ ++}; + +/* will be lec0, lec1, lec2 etc. */ +static char myname[] = "lecx"; @@ -10601,21 +10734,6 @@ + + return 0; +} -+void testi(struct sk_buff *skb, struct device *dev) -+{ -+ char dst_mac[] = {0,2,3,4,5,0}; -+ u8 *tlvs = kmalloc(6, GFP_KERNEL); -+ size_t sizeoftlvs = 6; -+ tlvs[0] = 1; -+ tlvs[1] = 2; -+ tlvs[2] = 3; -+ tlvs[3] = 4; -+ tlvs[4] = 1; -+ tlvs[5] = 42; -+ -+ lane2_resolve(dst_mac, 1, dev, &tlvs, &sizeoftlvs); -+ kfree(tlvs); -+} + +static int +lec_send_packet(struct sk_buff *skb, struct device *dev) @@ -10629,7 +10747,6 @@ + int i=0; +#endif /* DUMP_PACKETS >0 */ + -+ /* testi(skb, dev); */ + DPRINTK("Lec_send_packet called\n"); + if (!priv->lecd) { + printk("%s:No lecd attached\n",dev->name); @@ -10839,10 +10956,14 @@ + struct device *dev = (struct device*)vcc->proto_data; + struct lec_priv *priv = (struct lec_priv*)dev->priv; + struct atmlec_msg *mesg; ++ struct lec_arp_table *entry; + int i; ++ char *tmp; /* FIXME */ + + atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse); + mesg = (struct atmlec_msg *)skb->data; ++ tmp = skb->data; ++ tmp += sizeof(struct atmlec_msg); + DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type); + switch(mesg->type) { + case l_set_mac_addr: @@ -10865,15 +10986,24 @@ + case l_flush_complete: + lec_flush_complete(priv, mesg->content.normal.flag); + break; ++ case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */ ++ entry = lec_arp_find(priv, mesg->content.normal.mac_addr); ++ lec_arp_remove(priv->lec_arp_tables, entry); ++ ++ if (mesg->content.normal.no_source_le_narp) ++ break; ++ /* FALL THROUGH */ + case l_arp_update: + lec_arp_update(priv, mesg->content.normal.mac_addr, + mesg->content.normal.atm_addr, -+ mesg->content.normal.flag); ++ mesg->content.normal.flag, ++ mesg->content.normal.targetless_le_arp); ++ DPRINTK("lec: in l_arp_update\n"); + if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */ -+ printk("lec: LANE2 3.1.5, got tlvs\n"); -+ lane2_associate_ind(priv, ++ DPRINTK("lec: LANE2 3.1.5, got tlvs\n"); ++ lane2_associate_ind(dev, + mesg->content.normal.mac_addr, -+ (u8 *)mesg+1, mesg->sizeoftlvs); ++ tmp, mesg->sizeoftlvs); + } + break; + case l_config: @@ -10891,6 +11021,10 @@ + priv->flush_timeout = (mesg->content.config.flush_timeout*HZ); + priv->path_switching_delay = + (mesg->content.config.path_switching_delay*HZ); ++ priv->lane_version = mesg->content.config.lane_version; /* LANE2 */ ++ priv->lane2_ops = NULL; ++ if (priv->lane_version > 1) ++ priv->lane2_ops = &lane2_ops; + break; + case l_flush_tran_id: + lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr, @@ -10927,8 +11061,8 @@ + printk("%s lec_atm_close: closing with messages pending\n", + dev->name); + while ((skb = skb_dequeue(&vcc->recvq))) { -+ dev_kfree_skb(skb); + atm_return(vcc, skb->truesize); ++ dev_kfree_skb(skb); + } + + printk("%s: Shut down!\n", dev->name); @@ -10990,8 +11124,12 @@ + mesg = (struct atmlec_msg *)skb->data; + memset(mesg, 0, sizeof(struct atmlec_msg)); + mesg->type = type; ++ if (data != NULL) ++ mesg->sizeoftlvs = data->len; + if (mac_addr) + memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN); ++ else ++ mesg->content.normal.targetless_le_arp = 1; + if (atm_addr) + memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); + @@ -11001,10 +11139,9 @@ + wake_up(&priv->lecd->sleep); + + if (data != NULL) { -+ printk("lec: about to send %d bytes of data\n", data->len); -+ mesg->sizeoftlvs = data->len; ++ DPRINTK("lec: about to send %d bytes of data\n", data->len); + if (atm_charge(priv->lecd, data->truesize) == 0) -+ DPRINTK("lec: send_to_lecd, atm_charge()\n"); ++ printk("lec: send_to_lecd, atm_charge()\n"); + skb_queue_tail(&priv->lecd->recvq, data); + wake_up(&priv->lecd->sleep); + } @@ -11186,8 +11323,9 @@ + return -EADDRINUSE; + } + lec_arp_init(priv); ++ priv->itfnum = i; /* LANE2 addition */ + priv->lecd = vcc; -+ bind_vcc(vcc,&lecatm_dev); ++ bind_vcc(vcc, &lecatm_dev); + + vcc->proto_data = dev_lec[i]; + vcc->flags |= ATM_VF_READY | ATM_VF_META; @@ -11207,58 +11345,69 @@ + if (dev_lec[i]->flags & IFF_UP) { + dev_lec[i]->tbusy = 0; + dev_lec[i]->start = 1; -+ printk("lec.c: lecd_attach() upping device\n"); + } + MOD_INC_USE_COUNT; + return i; +} + -+#ifdef MODULE -+#include -+extern void atm_lane_setup (int (*attach)(struct atm_vcc *vcc, int arg), -+ int (*mcast)(struct atm_vcc *vcc, int arg), -+ int (*vcc)(struct atm_vcc *vcc, void *arg), -+ struct device **(*dev_lec_ptr)(void)); -+#ifndef LEC_VERSION -+#define LEC_VERSION "0.34" -+#endif ++void atm_lane_init_ops(struct atm_lane_ops *ops) ++{ ++ ops->lecd_attach = lecd_attach; ++ ops->mcast_attach = lec_mcast_attach; ++ ops->vcc_attach = lec_vcc_attach; ++ ops->get_lecs = get_dev_lec; + ++ printk("lec.c: " __DATE__ " " __TIME__ " initialized\n"); ++ ++ return; ++} ++ ++#ifdef MODULE +int init_module(void) +{ -+ printk("lec.c: v. %s.\n", LEC_VERSION); ++ extern struct atm_lane_ops atm_lane_ops; ++ ++ atm_lane_init_ops(&atm_lane_ops); + -+ atm_lane_setup(lecd_attach, lec_mcast_attach, -+ lec_vcc_attach, get_dev_lec); + return 0; +} + +void cleanup_module(void) +{ ++ int i; ++ extern struct atm_lane_ops atm_lane_ops; ++ + if (MOD_IN_USE) { -+ printk(KERN_NOTICE "lec: Device busy, remove delayed.\n"); ++ printk(KERN_NOTICE "lec.c: module in use\n"); ++ return; + } -+ else { -+ int i; -+ atm_lane_setup(NULL, NULL, NULL, NULL); -+ for (i = 0; i < MAX_LEC_ITF; i++) { -+ if (dev_lec[i] != NULL) { -+ unregister_netdev(dev_lec[i]); -+ kfree(dev_lec[i]->priv); -+ kfree(dev_lec[i]); -+ dev_lec[i] = NULL; -+ } ++ ++ atm_lane_ops.lecd_attach = NULL; ++ atm_lane_ops.mcast_attach = NULL; ++ atm_lane_ops.vcc_attach = NULL; ++ atm_lane_ops.get_lecs = NULL; ++ ++ for (i = 0; i < MAX_LEC_ITF; i++) { ++ if (dev_lec[i] != NULL) { ++ unregister_netdev(dev_lec[i]); ++ kfree(dev_lec[i]->priv); ++ kfree(dev_lec[i]); ++ dev_lec[i] = NULL; + } -+ return; + } -+} + ++ return; ++} +#endif /* MODULE */ + +/* + * LANE2: 3.1.3, LE_RESOLVE.request + * Non force allocates memory and fills in *tlvs, fills in *sizeoftlvs. ++ * If sizeoftlvs == NULL the default TLVs associated with with this ++ * lec will be used. ++ * If dst_mac == NULL, targetless LE_ARP will be sent + */ -+int lane2_resolve(u8 *dst_mac, int force, struct device *dev, u8 **tlvs, u32 *sizeoftlvs) ++static int lane2_resolve(struct device *dev, u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs) +{ + struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_arp_table *table; @@ -11280,13 +11429,17 @@ + return 0; + } + -+ skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC); -+ if (skb == NULL) -+ return -1; -+ skb->len = *sizeoftlvs; -+ memcpy(skb->data, *tlvs, *sizeoftlvs); -+ retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb); -+ ++ if (sizeoftlvs == NULL) ++ retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL); ++ ++ else { ++ skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC); ++ if (skb == NULL) ++ return -1; ++ skb->len = *sizeoftlvs; ++ memcpy(skb->data, *tlvs, *sizeoftlvs); ++ retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb); ++ } + return retval; +} + @@ -11295,16 +11448,17 @@ + * LANE2: 3.1.4, LE_ASSOCIATE.request + * Associate the *tlvs with the *lan_dst address. + * Will overwrite any previous association -+ * Returns 1 for success, 0 for fail (out of memory, wrong lan_dst) ++ * Returns 1 for success, 0 for failure (out of memory) + * -+ * Do we need to check the arp table for *lan_dst? + */ -+int lane2_associate_req (struct device *dev, u8 *lan_dst, ++static int lane2_associate_req (struct device *dev, u8 *lan_dst, + u8 *tlvs, u32 sizeoftlvs) +{ ++ int retval; ++ struct sk_buff *skb; + struct lec_priv *priv = (struct lec_priv*)dev->priv; + -+ if ( memcmp(lan_dst, dev->dev_addr, 6) != 0 ) ++ if ( memcmp(lan_dst, dev->dev_addr, ETH_ALEN) != 0 ) + return (0); /* not our mac address */ + + kfree(priv->tlvs); /* NULL if there was no previous association */ @@ -11315,6 +11469,14 @@ + priv->sizeoftlvs = sizeoftlvs; + memcpy(priv->tlvs, tlvs, sizeoftlvs); + ++ skb = alloc_skb(sizeoftlvs, GFP_ATOMIC); ++ if (skb == NULL) ++ return 0; ++ skb->len = sizeoftlvs; ++ memcpy(skb->data, tlvs, sizeoftlvs); ++ retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb); ++ if (retval != 0) ++ printk("lec.c: lane2_associate_req() failed\n"); + /* If the previous association has changed we must + * somehow notify other LANE entities about the change + */ @@ -11325,9 +11487,10 @@ + * LANE2: 3.1.5, LE_ASSOCIATE.indication + * + */ -+void lane2_associate_ind (struct lec_priv *priv, u8 *mac_addr, u8 *tlvs, u32 sizeoftlvs) ++static void lane2_associate_ind (struct device *dev, u8 *mac_addr, u8 *tlvs, u32 sizeoftlvs) +{ + int i = 0; ++ struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_arp_table *entry = lec_arp_find(priv, mac_addr); + + if (entry == NULL) @@ -11342,18 +11505,22 @@ + entry->sizeoftlvs = sizeoftlvs; + memcpy(entry->tlvs, tlvs, sizeoftlvs); + -+ printk("lec.c: lane2_associate_ind() associated\n "); ++#if 0 ++ printk("lec.c: lane2_associate_ind()\n"); + printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs); + while (i < sizeoftlvs) + printk("%02x ", tlvs[i++]); + + printk("\n"); ++#endif + -+ -+ -+ -+ -+ ++ /* tell MPOA about the TLVs we saw */ ++ if (priv->lane2_ops && priv->lane2_ops->associate_indicator) { ++ priv->lane2_ops->associate_indicator(dev, mac_addr, ++ tlvs, sizeoftlvs); ++ } ++ else ++ printk("lane:(%s) lane2_associate_ind: could not notify MPOA\n", dev->name); + return; +} + @@ -11429,20 +11596,27 @@ +{ + if (entry->vcc) { + entry->vcc->push = entry->old_push; ++#if 0 /* August 6, 1998 */ + entry->vcc->flags |= ATM_VF_RELEASED; + entry->vcc->flags &= ~ATM_VF_READY; ++#endif ++ atm_async_release_vcc(entry->vcc, -EPIPE); + entry->vcc = NULL; + } + if (entry->recv_vcc) { + entry->recv_vcc->push = entry->old_recv_push; ++#if 0 + entry->recv_vcc->flags |= ATM_VF_RELEASED; + entry->recv_vcc->flags &= ~ATM_VF_READY; ++#endif ++ atm_async_release_vcc(entry->recv_vcc, -EPIPE); + entry->recv_vcc = NULL; + } +} + +/* + * Insert entry to lec_arp_table ++ * LANE2: Add to the end of the list to satisfy 8.1.13 + */ +static __inline__ void +lec_arp_put(struct lec_arp_table **lec_arp_tables, @@ -11450,14 +11624,23 @@ +{ + unsigned short place; + unsigned long flags; ++ struct lec_arp_table *tmp; + + save_flags(flags); + cli(); + + place = HASH(to_put->mac_addr[ETH_ALEN-1]); -+ to_put->next = lec_arp_tables[place]; -+ lec_arp_tables[place] = to_put; ++ tmp = lec_arp_tables[place]; ++ to_put->next = NULL; ++ if (tmp == NULL) ++ lec_arp_tables[place] = to_put; + ++ else { /* add to the end */ ++ while (tmp->next) ++ tmp = tmp->next; ++ tmp->next = to_put; ++ } ++ + restore_flags(flags); + DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + 0xff&to_put->mac_addr[0], 0xff&to_put->mac_addr[1], @@ -11876,8 +12059,9 @@ + + DPRINTK("About to expire: %lx - %lx > %lx\n", + now,entry->last_used, time_to_check); -+ if((now-entry->last_used > time_to_check) && -+ !(entry->flags & LEC_PERMANENT_FLAG)) { ++ if( (now-entry->last_used > time_to_check) && ++ !(entry->flags & LEC_PERMANENT_FLAG) && ++ !(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */ + /* Remove entry */ + DPRINTK("LEC:Entry timed out\n"); + next = entry->next; @@ -11918,11 +12102,23 @@ +struct atm_vcc* +lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find) +{ ++ unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; + struct lec_arp_table *entry; + + if (mac_to_find[0]&0x01) { -+ return priv->mcast_vcc; ++ switch (priv->lane_version) { ++ case 1: ++ return priv->mcast_vcc; ++ break; ++ case 2: /* LANE2 wants arp for multicast addresses */ ++ if ( memcmp(mac_to_find, &bus_mac, ETH_ALEN) == 0) ++ return priv->mcast_vcc; ++ break; ++ default: ++ break; ++ } + } ++ + entry = lec_arp_find(priv, mac_to_find); + + if (entry) { @@ -11999,14 +12195,22 @@ + */ +void +lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, -+ unsigned char *atm_addr, unsigned long remoteflag) ++ unsigned char *atm_addr, unsigned long remoteflag, ++ unsigned int targetless_le_arp) +{ + struct lec_arp_table *entry, *tmp; + int i; + -+ DPRINTK("LEC:lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", ++ DPRINTK("lec:%s", (targetless_le_arp) ? "targetless ": " "); ++ DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3], + mac_addr[4],mac_addr[5]); ++ ++ entry = lec_arp_find(priv, mac_addr); ++ if (entry == NULL && targetless_le_arp) ++ return; /* LANE2: ignore targetless LE_ARPs for which ++ * we have no entry in the cache. 7.1.30 ++ */ + lec_arp_lock(priv); + if (priv->lec_arp_empty_ones) { + entry = priv->lec_arp_empty_ones; @@ -12409,8 +12613,8 @@ +} + --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/lec.h Tue Aug 4 17:58:20 1998 -@@ -0,0 +1,112 @@ ++++ work/net/atm/lec.h Tue Aug 11 19:46:26 1998 +@@ -0,0 +1,143 @@ +/* + * + * Lan Emulation client header file @@ -12444,6 +12648,32 @@ +}; + +/* ++ * Operations that LANE2 capable device can do. Two first functions ++ * are used to make the device do things. See spec 3.1.3 and 3.1.4. ++ * ++ * The third function is intented for the MPOA component sitting on ++ * top of the LANE device. The MPOA component assigns it's own function ++ * to (*associate_indicator)() and the LANE device will use that ++ * function to tell about TLVs it sees floating through. ++ * ++ */ ++struct lane2_ops { ++ int (*resolve)(struct device *dev, u8 *dst_mac, int force, ++ u8 **tlvs, u32 *sizeoftlvs); ++ int (*associate_req)(struct device *dev, u8 *lan_dst, ++ u8 *tlvs, u32 sizeoftlvs); ++ void (*associate_indicator)(struct device *dev, u8 *mac_addr, ++ u8 *tlvs, u32 sizeoftlvs); ++}; ++ ++struct atm_lane_ops { ++ int (*lecd_attach)(struct atm_vcc *vcc, int arg); ++ int (*mcast_attach)(struct atm_vcc *vcc, int arg); ++ int (*vcc_attach)(struct atm_vcc *vcc, void *arg); ++ struct device **(*get_lecs)(void); ++}; ++ ++/* + * ATM LAN Emulation supports both LLC & Dix Ethernet EtherType + * frames. + * 1. Dix Ethernet EtherType frames encoded by placing EtherType @@ -12507,9 +12737,11 @@ + delivered to the recipient (C22) */ + unsigned long path_switching_delay; + -+ u8 *tlvs; /* LANE2: TLVs are new */ -+ u32 sizeoftlvs; /* The size of the tlv array in bytes */ -+ ++ u8 *tlvs; /* LANE2: TLVs are new */ ++ u32 sizeoftlvs; /* The size of the tlv array in bytes */ ++ int lane_version; /* LANE2 */ ++ int itfnum; /* e.g. 2 for lec2, 5 for lec5 */ ++ struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */ +}; + +int lecd_attach(struct atm_vcc *vcc, int arg); @@ -12521,10 +12753,13 @@ + atmlec_msg_type type, unsigned char *mac_addr, + unsigned char *atm_addr, struct sk_buff *data); +void lec_push(struct atm_vcc *vcc, struct sk_buff *skb); ++ ++void atm_lane_init(void); ++void atm_lane_init_ops(struct atm_lane_ops *ops); +#endif _LEC_H_ + --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/lec_arpc.h Tue Aug 4 17:58:20 1998 ++++ work/net/atm/lec_arpc.h Tue Aug 11 19:46:26 1998 @@ -0,0 +1,112 @@ +/* + * Lec arp cache @@ -12633,135 +12868,2366 @@ +void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id); +void lec_arp_update(struct lec_priv *priv, + unsigned char *mac_addr, unsigned char *atm_addr, -+ unsigned long remoteflag); ++ unsigned long remoteflag, unsigned int targetless_le_arp); +void lec_set_flush_tran_id(struct lec_priv *priv, + unsigned char *mac_addr, unsigned long tran_id); + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/proc.c Wed Jun 17 02:59:45 1998 -@@ -0,0 +1,606 @@ -+/* net/atm/proc.c - ATM /proc interface */ -+ -+/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ -+ -+/* -+ * The mechanism used here isn't designed for speed but rather for convenience -+ * of implementation. We only return one entry per read system call, so we can -+ * be reasonably sure not to overrun the page and race conditions may lead to -+ * the addition or omission of some lines but never to any corruption of a -+ * line's internal structure. -+ * -+ * Making the whole thing slightly more efficient is left as an exercise to the -+ * reader. (Suggestions: wrapper which loops to get several entries per system -+ * call; or make --left slightly more clever to avoid O(n^2) characteristics.) -+ * I find it fast enough on my unloaded 266 MHz Pentium 2 :-) -+ */ -+ -+ -+#include ++++ work/net/atm/mpc.c Tue Aug 11 19:14:28 1998 +@@ -0,0 +1,1269 @@ ++#include +#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++#include ++#include ++ ++/* We are an ethernet device */ ++#include +#include -+#include -+#include -+#include -+#include /* for __initfunc */ ++#include ++#include ++#include ++#include ++#include +#include -+#include /* for HZ */ -+#include "resources.h" -+#include "common.h" /* atm_proc_init prototype */ -+#include "signaling.h" /* to get sigd - ugly too */ -+ -+#ifdef CONFIG_AREQUIPA -+#include -+void atm_push_arequipa(struct atm_vcc *vcc,struct sk_buff *skb); -+#endif ++#include /* for ip_fast_csum() */ ++#include ++#include ++#include + -+#ifdef CONFIG_ATM_CLIP -+#include -+#include "ipcommon.h" -+extern void clip_push(struct atm_vcc *vcc,struct sk_buff *skb); -+#endif ++/* And atm device */ ++#include ++#include ++#include ++/* Modular too */ ++#include ++#include + -+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +#include "lec.h" -+#include "lec_arpc.h" -+extern struct device **(*ptr_to_get_dev_lec)(void); ++#include "mpc.h" ++#include "tunable.h" ++#include "resources.h" /* for bind_vcc() */ ++ ++/* ++ * mpc.c: Implementation of MPOA client kernel part ++ */ ++ ++#if 1 ++#define dprintk printk /* debug */ ++#else ++#define dprintk(format,args...) +#endif + ++#if 0 ++#define ddprintk printk /* more debug */ ++#else ++#define ddprintk(format,args...) ++#endif + -+static ssize_t proc_atm_read(struct file *file,char *buf,size_t count, -+ loff_t *pos); + + -+static struct file_operations proc_atm_operations = { -+ NULL, /* lseek */ -+ proc_atm_read, /* read */ -+ NULL, /* write */ -+ NULL, /* readdir */ -+ NULL, /* select */ -+ NULL, /* ioctl */ -+ NULL, /* mmap */ -+ NULL, /* no special open code */ -+ NULL, /* no special release */ -+ NULL /* can't fsync */ -+}; ++#define MPOA_TAG_LEN 4 + -+struct inode_operations proc_atm_inode_operations = { -+ &proc_atm_operations, /* default ATM directory file-ops */ -+ NULL, /* create */ -+ NULL, /* lookup */ -+ NULL, /* link */ -+ NULL, /* unlink */ -+ NULL, /* symlink */ -+ NULL, /* mkdir */ -+ NULL, /* rmdir */ -+ NULL, /* mknod */ -+ NULL, /* rename */ -+ NULL, /* readlink */ -+ NULL, /* follow_link */ -+ NULL, /* readpage */ -+ NULL, /* writepage */ -+ NULL, /* bmap */ -+ NULL, /* truncate */ -+ NULL /* permission */ ++/* mpc_daemon -> kernel */ ++static void MPOA_trigger_rcvd (struct k_message *msg, struct mpoa_client *mpc); ++static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc); ++static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc); ++static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc); ++static void mps_death(struct k_message *msg, struct mpoa_client *mpc); ++static void clean_up(struct k_message *msg, struct mpoa_client *mpc); ++static void MPOA_cache_impos_rcvd(struct k_message *msg, struct mpoa_client *mpc); ++static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc); ++static void set_mps_mac_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc); ++ ++static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry); ++ ++static void mpoad_close(struct atm_vcc *vcc); ++static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb); ++ ++static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb); ++static int mpc_send_packet(struct sk_buff *skb, struct device *dev); ++static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev); ++static void mpc_timer_refresh(void); ++static void mpc_cache_check( unsigned long checking_time ); ++ ++static struct llc_snap_hdr llc_snap_mpoa_ctrl = { ++ 0xaa, 0xaa, 0x03, ++ {0x00, 0x00, 0x5e}, ++ {0x00, 0x03} /* For MPOA control PDUs */ ++}; ++static struct llc_snap_hdr llc_snap_mpoa_data = { ++ 0xaa, 0xaa, 0x03, ++ {0x00, 0x00, 0x00}, ++ {0x08, 0x00} /* This is for IP PDUs only */ ++}; ++static struct llc_snap_hdr llc_snap_mpoa_data_tagged = { ++ 0xaa, 0xaa, 0x03, ++ {0x00, 0x00, 0x00}, ++ {0x88, 0x4c} /* This is for tagged data PDUs */ ++}; ++ ++static struct notifier_block mpoa_notifier = { ++ mpoa_event_listener, ++ NULL, ++ 0 +}; + ++#ifdef CONFIG_PROC_FS ++extern int mpc_proc_init(void); ++extern void mpc_proc_clean(void); ++#endif + -+#define ENTRY(name) static struct proc_dir_entry atm_proc_entry_##name = \ -+ { 0, sizeof(#name)-1, #name, S_IFREG | S_IRUGO, 1, 0, 0, 0, \ -+ &proc_atm_inode_operations, NULL } -+#define REG(name) if (!error) error = proc_register(&atm_proc_root, \ -+ &atm_proc_entry_##name) -+#define INO(name) (atm_proc_entry_##name.low_ino) ++struct mpoa_client *mpcs = NULL; /* FIXME */ ++static struct timer_list mpc_timer; + + -+ENTRY(devices); -+ENTRY(pvc); -+ENTRY(svc); -+#ifdef CONFIG_ATM_CLIP -+ENTRY(arp); -+#endif -+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) -+ENTRY(lec); -+#endif -+#ifdef CONFIG_AREQUIPA -+ENTRY(arequipa); -+#endif ++static struct mpoa_client *find_mpc_by_itfnum(int itf) ++{ ++ struct mpoa_client *mpc; ++ ++ mpc = mpcs; /* our global linked list */ ++ while (mpc != NULL) { ++ if (mpc->dev_num == itf) ++ return mpc; ++ mpc = mpc->next; ++ } + ++ return NULL; /* not found */ ++} + -+static int atm_header(ino_t ino,char *buf) ++static struct mpoa_client *find_mpc_by_vcc(struct atm_vcc *vcc) +{ -+ if (ino == INO(devices)) -+ return sprintf(buf,"Itf Type ESI/\"MAC\"addr " ++ struct mpoa_client *mpc; ++ ++ mpc = mpcs; /* our global linked list */ ++ while (mpc != NULL) { ++ if (mpc->mpoad_vcc == vcc) ++ return mpc; ++ mpc = mpc->next; ++ } ++ ++ return NULL; /* not found */ ++} ++ ++static struct mpoa_client *find_mpc_by_lec(struct device *dev) ++{ ++ struct mpoa_client *mpc; ++ ++ mpc = mpcs; /* our global linked list */ ++ while (mpc != NULL) { ++ if (mpc->dev == dev) ++ return mpc; ++ mpc = mpc->next; ++ } ++ ++ return NULL; /* not found */ ++} ++ ++static struct device *find_lec_by_itfnum(int itf) ++{ ++ extern struct atm_lane_ops atm_lane_ops; /* in common.c */ ++ ++ if (atm_lane_ops.get_lecs == NULL) ++ return NULL; ++ ++ return atm_lane_ops.get_lecs()[itf]; /* FIXME: something better */ ++} ++ ++static struct mpoa_client *alloc_mpc(void) ++{ ++ struct mpoa_client *mpc; ++ ++ mpc = kmalloc(sizeof (struct mpoa_client), GFP_KERNEL); ++ if (mpc == NULL) ++ return NULL; ++ memset(mpc, 0, sizeof(struct mpoa_client)); ++#if 0 ++ mpc->ingress_lock = RW_LOCK_UNLOCKED; ++ mpc->egress_lock = RW_LOCK_UNLOCKED; ++#endif ++ mpc->next = mpcs; ++ atm_mpoa_init_cache(mpc); ++ mpcs = mpc; ++ ++ return mpc; ++} ++ ++/* ++ * ++ * start_mpc() puts the MPC on line. All the packets destined ++ * to the lec underneath us are now being monitored and ++ * shortcuts will be established. ++ * ++ */ ++static void start_mpc(struct mpoa_client *mpc, struct device *dev) ++{ ++ ++ printk("mpoa: (%s) start_mpc:\n", mpc->dev->name); ++ if (dev->hard_start_xmit == NULL) { ++ printk("mpoa: (%s) start_mpc: dev->hard_start_xmit == NULL, not starting\n", ++ dev->name); ++ return; ++ } ++ mpc->old_hard_start_xmit = dev->hard_start_xmit; ++ dev->hard_start_xmit = mpc_send_packet; ++ ++ return; ++} ++ ++static void stop_mpc(struct mpoa_client *mpc) ++{ ++ ++ printk("mpoa: (%s) stop_mpc:", mpc->dev->name); ++ ++ /* Lets not nullify lec device's dev->hard_start_xmit */ ++ if (mpc->dev->hard_start_xmit != mpc_send_packet) { ++ printk(" mpc already stopped, not fatal\n"); ++ return; ++ } ++ printk("\n"); ++ mpc->dev->hard_start_xmit = mpc->old_hard_start_xmit; ++ mpc->old_hard_start_xmit = NULL; ++ /* close_shortcuts(mpc); ??? FIXME */ ++ ++ return; ++} ++ ++static const char *mpoa_device_type_string (char type) ++{ ++ switch(type) { ++ case NON_MPOA: ++ return "non-MPOA device"; ++ break; ++ case MPS: ++ return "MPS"; ++ break; ++ case MPC: ++ return "MPC"; ++ break; ++ case MPS_AND_MPC: ++ return "both MPS and MPC"; ++ break; ++ default: ++ return "unspecified (non-MPOA) device"; ++ break; ++ } ++ ++ return ""; /* not reached */ ++} ++ ++/* ++ * lec device calls this via its dev->priv->lan2_ops->associate_indicator() ++ * when it sees a TLV in LE_ARP packet. ++ * We fill in the pointer above when we see a LANE2 lec initializing ++ * See LANE2 spec 3.1.5 ++ * ++ * Quite a big and ugly function but when you look at it ++ * all it does is to try to locate and parse MPOA Device ++ * Type TLV. ++ * We give our lec a pointer to this function and when the ++ * lec sees a TLV it uses the pointer to call this function. ++ * ++ */ ++static void lane2_assoc_ind(struct device *dev, uint8_t *mac_addr, ++ uint8_t *tlvs, uint32_t sizeoftlvs) ++{ ++ uint32_t type; ++ uint8_t length, mpoa_device_type, number_of_mps_macs; ++ struct k_message *mesg; ++ struct sk_buff *skb; ++ uint8_t *end_of_tlvs; ++ struct mpoa_client *mpc; ++ ++ mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */ ++ dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev->name); ++ dprintk("total length of all TLVs %d\n", sizeoftlvs); ++ ++ end_of_tlvs = tlvs + sizeoftlvs; ++ while (end_of_tlvs - tlvs >= 5) { ++ type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3]; ++ length = tlvs[4]; ++ tlvs += 5; ++ dprintk(" type 0x%x length %02x\n", type, length); ++ ++ if (type == 0) { ++ printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev->name); ++ return; ++ } ++ ++ if (type != TLV_MPOA_DEVICE_TYPE) { ++ tlvs += length; ++ continue; /* skip other TLVs */ ++ } ++ mpoa_device_type = *tlvs++; ++ number_of_mps_macs = *tlvs++; ++ printk("mpoa: (%s) MPOA device type '%s', ", dev->name, mpoa_device_type_string(mpoa_device_type)); ++ if (mpoa_device_type == MPS_AND_MPC && ++ length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */ ++ printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n", ++ dev->name); ++ continue; ++ } ++ if ((mpoa_device_type == MPS || mpoa_device_type == MPC) ++ && length < 22 + number_of_mps_macs*ETH_ALEN) { ++ printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n", ++ dev->name); ++ continue; ++ } ++ if (mpoa_device_type != MPS && mpoa_device_type != MPS_AND_MPC) { ++ printk("ignoring non-MPS device\n"); ++ if (mpoa_device_type == MPC) tlvs += 20; ++ continue; /* we are only interested in MPSs */ ++ } ++ if (number_of_mps_macs == 0 && mpoa_device_type == MPS_AND_MPC) { ++ printk("\nmpoa: (%s) lane2_assoc_ind: MPS_AND_MPC has zero MACs\n", dev->name); ++ continue; /* someone should read the spec */ ++ } ++ printk("this MPS has %d MAC addresses\n", number_of_mps_macs); ++ ++ /* ok, now we can go and tell our daemon the control address of MPS */ ++ mpc = find_mpc_by_lec(dev); ++ skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); ++ if (skb == NULL) { ++ printk("mpoa: (%s) lane2_assoc_ind: alloc_skb()\n", dev->name); ++ return; ++ } ++ memcpy (mpc->mps_ctrl_addr, tlvs, ATM_ESA_LEN); ++ ++ mesg = (struct k_message *)skb->data; ++ mesg->type = SET_MPS_CTRL_ADDR; ++ memcpy(mesg->MPS_ctrl, tlvs, ATM_ESA_LEN); ++ msg_to_mpoad(mesg, mpc); ++ ++ tlvs += 20; if (mpoa_device_type == MPS_AND_MPC) tlvs += 20; ++ /* collect the MPS MAC addresses */ ++ if (mpc->number_of_mps_macs < number_of_mps_macs) { ++ kfree(mpc->mps_macs); /* need more space */ ++ mpc->mps_macs = kmalloc(number_of_mps_macs*ETH_ALEN, GFP_KERNEL); ++ if (mpc->mps_macs == NULL) { ++ printk("mpoa: (%s) lane2_assoc_ind: out of mem\n", dev->name); ++ return; ++ } ++ } ++ while (number_of_mps_macs > 0) { ++ memcpy(mpc->mps_macs, tlvs, ETH_ALEN); ++ tlvs += ETH_ALEN; number_of_mps_macs--; ++ } ++ } ++ if (end_of_tlvs - tlvs != 0) ++ printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n", ++ dev->name, end_of_tlvs - tlvs); ++ return; ++} ++ ++/* FIXME: tarvitsee työtä */ ++static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) ++{ ++ in_cache_entry *entry; ++ struct iphdr *iph; ++ char *buff; ++ uint32_t ipaddr = 0; ++ ++ static struct { ++ struct llc_snap_hdr hdr; ++ uint32_t tag; ++ } tagged_llc_snap_hdr = { ++ {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}}, ++ 0 ++ }; ++ ++ buff = skb->data + mpc->dev->hard_header_len; ++ iph = (struct iphdr *)buff; ++ ipaddr = iph->daddr; ++ ++ ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr); ++ ++ ++ entry = mpc->in_ops->search(ipaddr, mpc); ++ if (entry == NULL) { ++ mpc->in_ops->new_entry(ipaddr, mpc); ++ return 1; ++ } ++ if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){ /* threshold not exceeded or VCC not ready */ ++ ddprintk("mpoa: (%s) send_via_shortcut() cache_hit() returns != OPEN\n", mpc->dev->name); ++ return 1; ++ } ++ ++ ddprintk("mpoa: (%s) send_via_shortcut() using shortcut\n", mpc->dev->name); ++ /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */ ++ if (iph->ttl <= 1) { ++ ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl); ++ return 1; ++ } ++ iph->ttl--; ++ iph->check = 0; ++ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); ++ ++ if (entry->ctrl_info.tag != 0) { ++ ddprintk("mpoa: (%s) send_via_shortcut() adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag); ++ tagged_llc_snap_hdr.tag = entry->ctrl_info.tag; ++ skb_pull(skb, LEC_HEADER_LEN); /* get rid of LANE+Eth header */ ++ skb_push(skb, sizeof(tagged_llc_snap_hdr)); /* add LLC/SNAP header */ ++ memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr)); ++ } else { ++ skb_pull(skb, LEC_HEADER_LEN); /* get rid of LANE+Eth header */ ++ skb_push(skb, sizeof(struct llc_snap_hdr)); /* add LLC/SNAP header + tag */ ++ memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)); ++ } ++ ++ atomic_add(skb->truesize, &entry->shortcut->tx_inuse); ++ entry->shortcut->dev->ops->send(entry->shortcut, skb); ++ entry->packets_fwded++; ++ ++ return 0; ++} ++ ++/* ++ * Probably needs some error checks and locking, not sure... ++ */ ++static int mpc_send_packet(struct sk_buff *skb, struct device *dev) ++{ ++ int retval; ++ struct mpoa_client *mpc; ++ int i = 0; ++ ++ mpc = find_mpc_by_lec(dev); /* this should NEVER fail */ ++ if(mpc == NULL) { ++ printk("mpoa: (%s) mpc_send_packet: no MPC found\n", dev->name); ++ goto non_ip; ++ } ++ ++ if ( ((struct ethhdr *)(skb->data + 2))->h_proto != htons(ETH_P_IP) ) ++ goto non_ip; /* Multi-Protocol Over ATM :-) */ ++ ++ while (i < mpc->number_of_mps_macs) { ++ if (memcmp(skb->data + 2, (mpc->mps_macs + i*ETH_ALEN), ETH_ALEN) == 0) ++ if ( send_via_shortcut(skb, mpc) == 0 ) /* try shortcut */ ++ return 0; /* success! */ ++ i++; ++ } ++ ++ non_ip: ++ retval = mpc->old_hard_start_xmit(skb,dev); ++ ++ return retval; ++} ++ ++int atm_mpoa_vcc_attach(struct atm_vcc *vcc, long arg) ++{ ++ int bytes_left; ++ struct mpoa_client *mpc; ++ struct atmmpc_ioc ioc_data; ++ in_cache_entry *in_entry; ++ uint32_t ipaddr; ++ unsigned char *ip; ++ ++ bytes_left = copy_from_user(&ioc_data, (void *)arg, sizeof(struct atmmpc_ioc)); ++ if (bytes_left != 0) { ++ printk("mpoa: mpc_vcc_attach: Short read (missed %d bytes) from userland\n", bytes_left); ++ return -EFAULT; ++ } ++ ipaddr = ioc_data.ipaddr; ++ if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF) ++ return -EINVAL; ++ ++ mpc = find_mpc_by_itfnum(ioc_data.dev_num); ++ if (mpc == NULL) ++ return -EINVAL; ++ ++ if (ioc_data.type == MPC_SOCKET_INGRESS) { ++ in_entry = mpc->in_ops->search(ipaddr, mpc); ++ if (in_entry == NULL || in_entry->entry_state < INGRESS_RESOLVED) { ++ printk("mpoa: (%s) mpc_vcc_attach: did not find RESOLVED entry from ingress cache\n", ++ mpc->dev->name); ++ return -EINVAL; ++ } ++ ip = (unsigned char*)&in_entry->ctrl_info.in_dst_ip; ++ printk("mpoa: (%s) mpc_vcc_attach() attaching ingress SVC, entry = %u.%u.%u.%u\n", ++ mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); ++ in_entry->shortcut = vcc; ++ } else { ++ printk("mpoa: (%s) mpc_vcc_attach() attaching egress SVC\n", mpc->dev->name); ++ } ++ ++ vcc->proto_data = mpc->dev; ++ vcc->push = mpc_push; ++ ++ return 0; ++} ++ ++/* ++ * ++ */ ++static void mpc_vcc_close(struct atm_vcc *vcc, struct device *dev) ++{ ++ struct mpoa_client *mpc; ++ in_cache_entry *in_entry; ++ eg_cache_entry *eg_entry; ++ ++ mpc = find_mpc_by_lec(dev); ++ if (mpc == NULL) { ++ printk("mpoa: (%s) mpc_vcc_close: close for unknown MPC\n", dev->name); ++ return; ++ } ++ ++ printk("mpoa: (%s) mpc_vcc_close:\n", dev->name); ++ in_entry = mpc->in_ops->search_by_vcc(vcc, mpc); ++ if (in_entry) { ++ unsigned char *ip = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; ++ dprintk("mpoa: (%s) mpoa_vcc_close, ingress SVC closed ip = %u.%u.%u.%u\n", ++ mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); ++ in_entry->shortcut = NULL; ++ } ++ eg_entry = mpc->eg_ops->search_by_vcc(vcc, mpc); ++ if (eg_entry) { ++ dprintk("mpoa: (%s) mpoa_vcc_close, egress SVC closed\n", mpc->dev->name); ++ eg_entry->shortcut = NULL; ++ } ++ ++ if (in_entry == NULL && eg_entry == NULL) ++ dprintk("mpoa: (%s) mpc_vcc_close: unused vcc closed\n", dev->name); ++ ++ return; ++} ++ ++static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) ++{ ++ struct device *dev = (struct device *)vcc->proto_data; ++ struct sk_buff *new_skb; ++ eg_cache_entry *eg; ++ struct mpoa_client *mpc; ++ uint32_t tag; ++ char *tmp; ++ ++ ddprintk("mpoa: (%s) mpc_push()\n", dev->name); ++ if (skb == NULL) { ++ printk("mpoa: (%s) mpc_push() null skb, closing VCC\n", dev->name); ++ mpc_vcc_close(vcc, dev); ++ return; ++ } ++ ++ skb->dev = dev; ++ if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) { ++ printk("mpoa: (%s) mpc_push() control packet arrived\n", dev->name); ++ skb_queue_tail(&vcc->recvq, skb); /* Pass control packets to daemon */ ++ wake_up(&vcc->sleep); ++ return; ++ } ++ ++ /* data coming over the shortcut */ ++ atm_return(vcc, skb->truesize); ++ ++ mpc = find_mpc_by_lec(dev); ++ if (mpc == NULL) { ++ printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name); ++ return; ++ } ++ ++ if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */ ++ ddprintk("mpoa: (%s) mpc_push() tagged data packet arrived\n", dev->name); ++ ++ } else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */ ++ printk("mpoa: (%s) mpc_push() non-tagged data packet arrived\n", dev->name); ++ printk(" mpc_push() non-tagged data unsupported, purging\n"); ++ kfree_skb(skb); ++ return; ++ } else { ++ printk("mpoa:(%s) mpc_push() garbage arrived, purging\n", dev->name); ++ kfree_skb(skb); ++ return; ++ } ++ ++ tmp = skb->data + sizeof(struct llc_snap_hdr); ++ tag = *(uint32_t *)tmp; ++ ++ eg = mpc->eg_ops->search_by_tag(tag, mpc); ++ if (eg == NULL) { ++ printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n", ++ dev->name,tag); ++ purge_egress_shortcut(vcc, NULL); ++ kfree_skb(skb); ++ return; ++ } ++ ++ /* ++ * See if ingress MPC is using shortcut we opened as a return channel. ++ * This means we have a bi-directional vcc opened by us. ++ */ ++ if (eg->shortcut == NULL) { ++ eg->shortcut = vcc; ++ printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name); ++ } ++ ++ skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */ ++ new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */ ++ kfree_skb(skb); ++ skb_push(new_skb, eg->ctrl_info.DH_length); /* add MAC header */ ++ memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length); ++ new_skb->mac.raw = new_skb->data; ++ skb_pull(new_skb, ETH_HLEN); ++ ++ tmp = eg->ctrl_info.DLL_header + 2*ETH_ALEN; ++ memcpy(&new_skb->protocol, tmp, sizeof(uint16_t)); ++ if ( ntohs(new_skb->protocol) < 1536 ) { ++ printk("mpoa: (%s) mpc_push() received non-DIX Ethernet frame, purging\n", ++ dev->name); ++ kfree_skb(new_skb); ++ return; ++ } ++ ++ eg->packets_rcvd++; ++ ++ netif_rx(new_skb); ++ ++ return; ++} ++ ++static struct atmdev_ops mpc_ops = { /* only send is required */ ++ NULL, /* dev_close */ ++ NULL, /* open */ ++ mpoad_close, /* close */ ++ NULL, /* ioctl */ ++ NULL, /* getsockopt */ ++ NULL, /* setsockopt */ ++ msg_from_mpoad, /* send */ ++ NULL, /* sg_send */ ++ NULL, /* send_oam */ ++ NULL, /* phy_put */ ++ NULL, /* phy_get */ ++ NULL, /* feedback */ ++ NULL, /* change_qos */ ++ NULL, /* free_rx_skb */ ++ NULL /* proc_read */ ++}; ++ ++static struct atm_dev mpc_dev = { ++ &mpc_ops, /* device operations */ ++ NULL, /* PHY operations */ ++ "mpc", /* device type name */ ++ 42, /* device index (dummy) */ ++ NULL, /* VCC table */ ++ NULL, /* last VCC */ ++ NULL, /* per-device data */ ++ NULL, /* private PHY data */ ++ 0, /* device flags */ ++ NULL, /* local ATM address */ ++ { 0 } /* no ESI */ ++ /* rest of the members will be 0 */ ++}; ++ ++int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) ++{ ++ struct mpoa_client *mpc; ++ struct lec_priv *priv; ++ ++ if (mpcs == NULL) { ++ init_timer(&mpc_timer); ++ mpc_timer_refresh(); ++ ++ /* This lets us now how our LECs are doing */ ++ register_netdevice_notifier(&mpoa_notifier); ++ } ++ ++ mpc = find_mpc_by_itfnum(arg); ++ if (mpc == NULL) { ++ printk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg); ++ mpc = alloc_mpc(); ++ mpc->dev_num = arg; ++ mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */ ++ } ++ if (mpc->mpoad_vcc) { ++ printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg); ++ return -EADDRINUSE; ++ } ++ ++ if (mpc->dev) { /* check if the lec is LANE2 capable */ ++ priv = (struct lec_priv *)mpc->dev->priv; ++ if (priv->lane_version < 2) ++ mpc->dev = NULL; ++ else ++ priv->lane2_ops->associate_indicator = lane2_assoc_ind; ++ } ++ ++ mpc->mpoad_vcc = vcc; ++ bind_vcc(vcc, &mpc_dev); ++ vcc->flags |= ATM_VF_READY | ATM_VF_META; ++ if (mpc->dev) ++ start_mpc(mpc, mpc->dev); ++ MOD_INC_USE_COUNT; ++ ++ return arg; ++} ++ ++static void mpoad_close(struct atm_vcc *vcc) ++{ ++ unsigned long flags; ++ struct mpoa_client *mpc; ++ struct sk_buff *skb; ++ ++ mpc = find_mpc_by_vcc(vcc); ++ if (mpc == NULL) { ++ printk("mpoa: mpoad_close: did not find MPC\n"); ++ return; ++ } ++ if (!mpc->mpoad_vcc) { ++ printk("mpoa: mpoad_close: close for non-present mpoad\n"); ++ return; ++ } ++ ++ mpc->mpoad_vcc = NULL; ++ if (mpc->dev) { ++ struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv; ++ priv->lane2_ops->associate_indicator = NULL; ++ stop_mpc(mpc); ++ } ++ ++ /* clear the caches */ ++ write_lock_irqsave(&mpc->ingress_lock, flags); ++ while(mpc->in_ops->cache_remove(mpc->in_cache, mpc)); ++ write_unlock_irqrestore(&mpc->ingress_lock, flags); ++ ++ write_lock_irqsave(&mpc->egress_lock, flags); ++ while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc)); ++ write_unlock_irqrestore(&mpc->egress_lock, flags); ++ ++ while ( (skb = skb_dequeue(&vcc->recvq)) ){ ++ atm_return(vcc, skb->truesize); ++ kfree_skb(skb); ++ } ++ ++ printk("mpoa: (%s) going down\n", ++ (mpc->dev) ? mpc->dev->name : ""); ++ MOD_DEC_USE_COUNT; ++ ++ return; ++} ++ ++/* ++ * ++ */ ++static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb) ++{ ++ ++ struct mpoa_client *mpc = find_mpc_by_vcc(vcc); ++ struct k_message *mesg = (struct k_message*)skb->data; ++ atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse); ++ ++ if (mpc == NULL) { ++ printk("mpoa: msg_from_mpoad: no mpc found\n"); ++ return 0; ++ } ++ printk("mpoa: (%s) msg_from_mpoad:", (mpc->dev) ? mpc->dev->name : ""); ++ switch(mesg->type) { ++ case MPOA_RES_REPLY_RCVD: ++ printk(" mpoa_res_reply_rcvd.\n"); ++ MPOA_res_reply_rcvd(mesg, mpc); ++ break; ++ case MPOA_TRIGGER_RCVD: ++ printk(" mpoa_trigger_rcvd.\n"); ++ MPOA_trigger_rcvd(mesg, mpc); ++ break; ++ case INGRESS_PURGE_RCVD: ++ printk(" nhrp_purge_rcvd.\n"); ++ ingress_purge_rcvd(mesg, mpc); ++ break; ++ case EGRESS_PURGE_RCVD: ++ printk(" egress_purge_reply_rcvd.\n"); ++ egress_purge_rcvd(mesg, mpc); ++ break; ++ case MPS_DEATH: ++ printk(" mps_death.\n"); ++ mps_death(mesg, mpc); ++ break; ++ case CACHE_IMPOS_RCVD: ++ printk(" cache_impos_rcvd.\n"); ++ MPOA_cache_impos_rcvd(mesg, mpc); ++ break; ++ case SET_MPC_CTRL_ADDR: ++ printk(" set_mpc_ctrl_addr\n"); ++ set_mpc_ctrl_addr_rcvd(mesg, mpc); ++ break; ++ case SET_MPS_MAC_ADDR: ++ printk(" set_mps_mac_addr\n"); ++ set_mps_mac_addr_rcvd(mesg, mpc); ++ break; ++ case CLEAN_UP_AND_EXIT: ++ printk(" clean_up_and_exit\n"); ++ clean_up(mesg, mpc); ++ break; ++ default: ++ printk(" unknown message %d\n", mesg->type); ++ break; ++ } ++ kfree_skb(skb); ++ ++ return 0; ++} ++ ++int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc) ++{ ++ struct sk_buff *skb; ++ ++ if (mpc == NULL || !mpc->mpoad_vcc) { ++ printk("mpoa: msg_to_mpoad: mesg %d to a non-existant mpoad\n", mesg->type); ++ return -ENXIO; ++ } ++ ++ skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); ++ if (skb == NULL) ++ return -ENOMEM; ++ skb_put(skb, sizeof(struct k_message)); ++ memcpy(skb->data, mesg, sizeof(struct k_message)); ++ if (atm_charge(mpc->mpoad_vcc, skb->truesize) == 0) { ++ printk("mpoa: msg_to_mpoad: atm_charge failed\n"); ++ return -ENOMEM; ++ } ++ ++ skb_queue_tail(&mpc->mpoad_vcc->recvq, skb); ++ wake_up(&mpc->mpoad_vcc->sleep); ++ ++ return 0; ++} ++ ++static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev_ptr) ++{ ++ struct device *dev; ++ struct mpoa_client *mpc; ++ struct lec_priv *priv; ++ ++ dev = (struct device *)dev_ptr; ++ if (dev->name == NULL || strncmp(dev->name, "lec", 3)) ++ return NOTIFY_DONE; /* we are only interested in lec:s */ ++ ++ switch (event) { ++ case NETDEV_REGISTER: /* a new lec device was allocated */ ++ priv = (struct lec_priv *)dev->priv; ++ if (priv->lane_version < 2) ++ break; ++ priv->lane2_ops->associate_indicator = lane2_assoc_ind; ++ mpc = find_mpc_by_itfnum(priv->itfnum); ++ if (mpc == NULL) { ++ printk("mpoa: mpoa_event_listener: allocating new mpc for %s\n", ++ dev->name); ++ mpc = alloc_mpc(); ++ if (mpc == NULL) { ++ printk("mpoa: mpoa_event_listener: no new mpc"); ++ break; ++ } ++ } ++ mpc->dev_num = priv->itfnum; ++ mpc->dev = dev; ++ printk("mpoa: (%s) was initialized\n", dev->name); ++ break; ++ case NETDEV_UNREGISTER: ++ /* the lec device was deallocated */ ++ mpc = find_mpc_by_lec(dev); ++ if (mpc == NULL) ++ break; ++ printk("mpoa: device (%s) was deallocated\n", dev->name); ++ stop_mpc(mpc); ++ mpc->dev = NULL; ++ break; ++ case NETDEV_UP: ++ /* the dev was ifconfig'ed up */ ++ mpc = find_mpc_by_lec(dev); ++ if (mpc == NULL) ++ break; ++ if (mpc->mpoad_vcc != NULL) { ++ start_mpc(mpc, dev); ++ } ++ break; ++ case NETDEV_DOWN: ++ /* the dev was ifconfig'ed down */ ++ /* this means dev->start == 0 and ++ * the flow of packets from the ++ * upper layer stops ++ */ ++ mpc = find_mpc_by_lec(dev); ++ if (mpc == NULL) ++ break; ++ if (mpc->mpoad_vcc != NULL) { ++ stop_mpc(mpc); ++ } ++ break; ++ case NETDEV_REBOOT: ++ case NETDEV_CHANGE: ++ case NETDEV_CHANGEMTU: ++ case NETDEV_CHANGEADDR: ++ case NETDEV_GOING_DOWN: ++ break; ++ default: ++ break; ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++/* ++ * Functions which are called after a message is received from mpcd. ++ * Msg is reused on purpose. ++ */ ++ ++ ++static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *client) ++{ ++ uint32_t dst_ip = msg->content.in_info.in_dst_ip; ++ in_cache_entry *entry; ++ ++ entry = client->in_ops->search(dst_ip, client); ++ if( entry == NULL ){ ++ entry = client->in_ops->new_entry(dst_ip, client); ++ entry->entry_state = INGRESS_RESOLVING; ++ msg->type = SND_MPOA_RES_RQST; ++ msg->content.in_info = entry->ctrl_info; ++ msg_to_mpoad(msg,client); ++ do_gettimeofday(&(entry->reply_wait)); ++ return; ++ } ++ ++ if( entry->entry_state == INGRESS_INVALID ){ ++ entry->entry_state = INGRESS_RESOLVING; ++ msg->type = SND_MPOA_RES_RQST; ++ msg->content.in_info = entry->ctrl_info; ++ msg_to_mpoad(msg,client); ++ do_gettimeofday(&(entry->reply_wait)); ++ return; ++ } ++ ++ printk("mpoa: (%s) MPOA_trigger_rcvd: entry already in resolving state\n", ++ (client->dev) ? client->dev->name : ""); ++ return; ++} ++ ++static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *client) ++{ ++ uint32_t dst_ip = msg->content.in_info.in_dst_ip; ++ in_cache_entry *entry = client->in_ops->search(dst_ip, client); ++ ++ dprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", client->dev->name, entry); ++ if(entry == NULL){ ++ printk("\nmpoa: (%s): ARGH, received res. reply for an entry that doesn't exist.\n", client->dev->name); ++ return; ++ } ++ printk(" entry_state = %d ", entry->entry_state); ++ ++ if (entry->entry_state == INGRESS_RESOLVED) { ++ printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", client->dev->name); ++ return; ++ } ++ ++ entry->ctrl_info = msg->content.in_info; ++ do_gettimeofday(&(entry->tv)); ++ do_gettimeofday(&(entry->reply_wait)); /* Used in refreshing func from now on */ ++ entry->refresh_time = 0; ++ printk("entry->shortcut = %p\n", entry->shortcut); ++ ++ if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL){ ++ entry->entry_state = INGRESS_RESOLVED; ++ return; /* Shortcut already open... */ ++ } ++ if (entry->shortcut == NULL) { ++ entry->entry_state = INGRESS_RESOLVED; ++ msg->type = OPEN_INGRESS_SVC; ++ msg_to_mpoad(msg,client); ++ return; ++ } ++ ++ printk("mpoa: (%s) MPOA_res_reply_rcvd: still here, impossible!\n", client->dev->name); ++ return; ++} ++ ++static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) ++{ ++ uint32_t dst_ip = msg->content.in_info.in_dst_ip; ++ unsigned char *ip = (unsigned char *)&dst_ip; ++ ++ in_cache_entry *entry = mpc->in_ops->search(dst_ip, mpc); ++ if( entry == NULL ){ ++ printk("mpoa: (%s): ingress_purge_rcvd: recieved a purge for an entry that doesn't exist, ", mpc->dev->name); ++ printk("ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]); ++ return; ++ } ++ ++ printk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" , ++ mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); ++ mpc->in_ops->cache_remove(entry, mpc); ++ ++ return; ++} ++ ++static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) ++{ ++ unsigned long flags; ++ uint32_t cache_id = msg->content.eg_info.cache_id; ++ eg_cache_entry *entry = mpc->eg_ops->search_by_cache_id(cache_id, mpc); ++ ++ if( entry == NULL ){ ++ printk("mpoa: (%s): egress_purge_rcvd: recieved a purge reply for an entry that doesn't exist\n", mpc->dev->name); ++ return; ++ } ++ ++ write_lock_irqsave(&mpc->egress_lock, flags); ++ mpc->eg_ops->cache_remove(entry, mpc); ++ write_unlock_irqrestore(&mpc->egress_lock, flags); ++ ++ return; ++} ++ ++static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) ++{ ++ struct k_message *purge_msg; ++ struct sk_buff *skb; ++ ++ dprintk("mpoa: purge_egress_shortcut:, entering\n"); ++ if (vcc == NULL) { ++ printk("mpoa: purge_egress_shortcut: vcc == NULL\n"); ++ return; ++ } ++ ++ skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); ++ if (skb == NULL) { ++ printk("mpoa: purge_egress_shortcut: out of memory\n"); ++ return; ++ } ++ ++ skb_put(skb, sizeof(struct k_message)); ++ memset(skb->data, 0, sizeof(struct k_message)); ++ purge_msg = (struct k_message *)skb->data; ++ purge_msg->type = DATA_PLANE_PURGE; ++ if (entry != NULL) ++ purge_msg->content.eg_info = entry->ctrl_info; ++ ++ if (atm_charge(vcc, skb->truesize) == 0) { ++ printk("mpoa: purge_egress_shortcut: atm_charge failed\n"); ++ return; ++ } ++ ++ skb_queue_tail(&vcc->recvq, skb); ++ wake_up(&vcc->sleep); ++ dprintk("mpoa: purge_egress_shortcut:, exiting:\n"); ++ ++ return; ++} ++ ++/* ++ * Our MPS died. Tell our daemon to send NHRP data plane purge to each ++ * of the egress shortcuts we have. ++ */ ++static void mps_death( struct k_message * msg, struct mpoa_client * mpc ) ++{ ++ ++ unsigned long flags; ++ eg_cache_entry *entry; ++ ++ printk("mpoa: (%s) mps_death:\n", mpc->dev->name); ++ ++ if(memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)){ ++ printk("mpoa: (%s) mps_death: wrong MPS\n", mpc->dev->name); ++ return; ++ } ++ ++ entry = mpc->eg_cache; ++ while (entry != NULL) { ++ purge_egress_shortcut(entry->shortcut, entry); ++ entry = entry->next; ++ } ++ ++ write_lock_irqsave(&mpc->ingress_lock, flags); ++ while(mpc->in_ops->cache_remove(mpc->in_cache, mpc)); ++ write_unlock_irqrestore(&mpc->ingress_lock, flags); ++ ++ write_lock_irqsave(&mpc->egress_lock, flags); ++ while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc)); ++ write_unlock_irqrestore(&mpc->egress_lock, flags); ++ ++ return; ++} ++ ++static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client * mpc){ ++ ++ uint16_t holding_time; ++ unsigned long flags; ++ eg_cache_entry *entry = mpc->eg_ops->search_by_cache_id(msg->content.eg_info.cache_id, mpc); ++ ++ holding_time = msg->content.eg_info.holding_time; ++ printk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n", ++ mpc->dev->name, entry, holding_time); ++ if(entry == NULL && holding_time) { ++ mpc->eg_ops->new_entry(msg, mpc); ++ return; ++ } ++ if(holding_time){ ++ mpc->eg_ops->update(entry, holding_time); ++ return; ++ } ++ ++ write_lock_irqsave(&mpc->egress_lock, flags); ++ mpc->eg_ops->cache_remove(entry, mpc); ++ write_unlock_irqrestore(&mpc->egress_lock, flags); ++ ++ ++ return; ++} ++ ++static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc) ++{ ++ struct lec_priv *priv; ++ int i, retval ; ++ ++ uint8_t tlv[4 + 1 + 1 + 1 + ATM_ESA_LEN]; ++ ++ tlv[0] = 00; tlv[1] = 0xa0; tlv[2] = 0x3e; tlv[3] = 0x2a; /* type */ ++ tlv[4] = 1 + 1 + ATM_ESA_LEN; /* length */ ++ tlv[5] = 0x02; /* MPOA client */ ++ tlv[6] = 0x00; /* number of MPS MAC addresses */ ++ ++ memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */ ++ memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN); ++ ++ printk("mpoa: (%s) setting MPC ctrl ATM address to ", mpc->dev->name); ++ for (i = 7; i < sizeof(tlv); i++) ++ printk("%02x ", tlv[i]); ++ printk("\n"); ++ ++ if (mpc->dev) { ++ priv = (struct lec_priv *)mpc->dev->priv; ++ retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv)); ++ if (retval == 0) ++ printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name); ++ retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL); ++ if (retval < 0) ++ printk("mpoa: (%s) targetless LE_ARP request failed\n", mpc->dev->name); ++ } ++ ++ return; ++} ++ ++static void set_mps_mac_addr_rcvd(struct k_message *msg, struct mpoa_client *client){ ++ if(client->number_of_mps_macs) ++ kfree(client->mps_macs); ++ client->mps_macs = kmalloc(ETH_ALEN,GFP_KERNEL); ++ if (client->mps_macs == NULL) { ++ printk("mpoa: set_mps_mac_addr_rcvd: out of memory\n"); ++ return; ++ } ++ client->number_of_mps_macs = 1; ++ memcpy(client->mps_macs, msg->MPS_ctrl, ETH_ALEN); ++ ++ return; ++} ++ ++static void clean_up(struct k_message *msg, struct mpoa_client *mpc){ ++ ++ unsigned long flags; ++ eg_cache_entry *entry; ++ msg->type = SND_EGRESS_PURGE; ++ ++ ++ read_lock_irqsave(&mpc->egress_lock, flags); ++ entry = mpc->eg_cache; ++ while(entry != NULL){ ++ msg->content.eg_info = entry->ctrl_info; ++ printk("mpoa: cache_id %u\n", entry->ctrl_info.cache_id); ++ msg_to_mpoad(msg, mpc); ++ entry = entry->next; ++ } ++ read_unlock_irqrestore(&mpc->egress_lock, flags); ++ ++ msg->type = DIE; ++ msg_to_mpoad(msg, mpc); ++ return; ++} ++ ++static void mpc_timer_refresh() ++{ ++ mpc_timer.expires = jiffies + (MPC_P2 * HZ); ++ mpc_timer.data = mpc_timer.expires; ++ mpc_timer.function = mpc_cache_check; ++ add_timer(&mpc_timer); ++ ++ return; ++} ++ ++static void mpc_cache_check( unsigned long checking_time ) ++{ ++ struct mpoa_client *mpc = mpcs; ++ static unsigned long previous_resolving_check_time = 0; ++ static unsigned long previous_refresh_time = 0; ++ ++ while( mpc != NULL ){ ++ mpc->in_ops->clear_count(mpc); ++ mpc->eg_ops->clear_expired(mpc); ++ if(checking_time - previous_resolving_check_time > MPC_P4 * HZ ){ ++ mpc->in_ops->check_resolving(mpc); ++ previous_resolving_check_time = checking_time; ++ } ++ if(checking_time - previous_refresh_time > MPC_P5 * HZ ){ ++ mpc->in_ops->refresh(mpc); ++ previous_refresh_time = checking_time; ++ } ++ mpc = mpc->next; ++ } ++ mpc_timer_refresh(); ++ ++ return; ++} ++ ++void atm_mpoa_init_ops(struct atm_mpoa_ops *ops) ++{ ++ ops->mpoad_attach = atm_mpoa_mpoad_attach; ++ ops->vcc_attach = atm_mpoa_vcc_attach; ++ ++#ifdef CONFIG_PROC_FS ++ if(mpc_proc_init() != 0) ++ printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n"); ++ else ++ printk(KERN_INFO "mpoa: /proc/mpoa initialized\n"); ++#endif ++ ++ printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); ++ ++ return; ++} ++ ++#ifdef MODULE ++int init_module(void) ++{ ++ extern struct atm_mpoa_ops atm_mpoa_ops; ++ ++ atm_mpoa_init_ops(&atm_mpoa_ops); ++ ++ return 0; ++} ++ ++void cleanup_module(void) ++{ ++ extern struct atm_mpoa_ops atm_mpoa_ops; ++ struct mpoa_client *mpc, *tmp; ++ struct lec_priv *priv; ++ ++ if (MOD_IN_USE) { ++ printk("mpc.c: module in use\n"); ++ return; ++ } ++#ifdef CONFIG_PROC_FS ++ mpc_proc_clean(); ++#endif ++ ++ del_timer(&mpc_timer); ++ unregister_netdevice_notifier(&mpoa_notifier); ++ atm_mpoa_ops.mpoad_attach = NULL; ++ atm_mpoa_ops.vcc_attach = NULL; ++ ++ mpc = mpcs; ++ mpcs = NULL; ++ while (mpc != NULL) { ++ tmp = mpc->next; ++ if (mpc->dev != NULL) { ++ stop_mpc(mpc); ++ priv = (struct lec_priv *)mpc->dev->priv; ++ if (priv->lane2_ops != NULL) ++ priv->lane2_ops->associate_indicator = NULL; ++ } ++ ddprintk("mpoa: cleanup_module: about to clear caches\n"); ++ while(mpc->in_ops->cache_remove(mpc->in_cache, mpc)); ++ while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc)); ++ ddprintk("mpoa: cleanup_module: caches cleared\n"); ++ kfree(mpc->mps_macs); ++ memset(mpc, 0, sizeof(struct mpoa_client)); ++ ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc); ++ kfree(mpc); ++ ddprintk("mpoa: cleanup_module: kfree() done\n"); ++ ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp); ++ mpc = tmp; ++ } ++ ++ return; ++} ++#endif /* MODULE */ ++ +--- /dev/null Tue Jan 1 05:00:00 1980 ++++ work/net/atm/mpc.h Tue Aug 11 19:14:28 1998 +@@ -0,0 +1,59 @@ ++#ifndef _MPC_H_ ++#define _MPC_H_ ++ ++#include ++#include ++#include ++#include "mpoa_caches.h" ++ ++/* kernel -> mpc-daemon */ ++int msg_to_mpoad(struct k_message *msg, struct mpoa_client *mpc); ++ ++/* Functions for ioctl(ATMMPC_*) operations */ ++int atm_mpoa_mpoad_attach(struct atm_vcc *vcc, int arg); ++int atm_mpoa_vcc_attach(struct atm_vcc *vcc, long arg); ++ ++ ++struct mpoa_client { ++ struct mpoa_client *next; ++ struct device *dev; /* lec in question */ ++ int dev_num; /* e.g. 2 for lec2 */ ++ int (*old_hard_start_xmit)(struct sk_buff *skb, struct device *dev); ++ struct atm_vcc *mpoad_vcc; /* control channel to mpoad */ ++ uint8_t mps_ctrl_addr[ATM_ESA_LEN]; /* MPS control ATM address */ ++ uint8_t our_ctrl_addr[ATM_ESA_LEN]; /* MPC's control ATM address */ ++ ++ rwlock_t ingress_lock; ++ struct in_cache_ops *in_ops; /* ingress cache operations */ ++ in_cache_entry *in_cache; /* the ingress cache of this MPC */ ++ ++ rwlock_t egress_lock; ++ struct eg_cache_ops *eg_ops; /* egress cache operations */ ++ eg_cache_entry *eg_cache; /* the egress cache of this MPC */ ++ ++ uint8_t *mps_macs; /* array of MPS MAC addresses, >=1 */ ++ int number_of_mps_macs; /* number of the above MAC addresses */ ++}; ++ ++/* TLVs this MPC recognizes */ ++#define TLV_MPOA_DEVICE_TYPE 0x00a03e2a ++ ++/* MPOA device types in MPOA Device Type TLV */ ++#define NON_MPOA 0 ++#define MPS 1 ++#define MPC 2 ++#define MPS_AND_MPC 3 ++ ++ ++/* Functions to call during ioctl(ATMMPC, ) */ ++struct atm_mpoa_ops { ++ int (*mpoad_attach)(struct atm_vcc *vcc, int arg); /* attach mpoa daemon */ ++ int (*vcc_attach)(struct atm_vcc *vcc, long arg); /* attach shortcut vcc */ ++}; ++ ++/* Boot/module initialization function */ ++void atm_mpoa_init(void); ++void atm_mpoa_init_ops(struct atm_mpoa_ops *ops); ++ ++#endif /* _MPC_H_ */ ++ +--- /dev/null Tue Jan 1 05:00:00 1980 ++++ work/net/atm/mpoa_caches.c Tue Aug 11 19:14:28 1998 +@@ -0,0 +1,507 @@ ++#include ++#include ++#include ++ ++#include "mpoa_caches.h" ++#include "mpc.h" ++ ++/* ++ * mpoa_caches.c: Implementation of ingress and egress cache ++ * handling functions ++ */ ++ ++#if 0 ++#define dprintk printk /* debug */ ++#else ++#define dprintk(format,args...) ++#endif ++ ++#if 0 ++#define ddprintk printk /* more debug */ ++#else ++#define ddprintk(format,args...) ++#endif ++ ++static in_cache_entry *in_cache_search(uint32_t dst_ip, ++ struct mpoa_client *client) ++{ ++ unsigned long flags; ++ in_cache_entry *entry; ++ ++ read_lock_irqsave(&client->ingress_lock, flags); ++ entry = client->in_cache; ++ while(entry != NULL){ ++ if( entry->ctrl_info.in_dst_ip == dst_ip ){ ++ read_unlock_irqrestore(&client->ingress_lock, flags); ++ return entry; ++ } ++ entry = entry->next; ++ } ++ read_unlock_irqrestore(&client->ingress_lock, flags); ++ ++ return NULL; ++} ++ ++static in_cache_entry *in_cache_search_by_vcc(struct atm_vcc *vcc, ++ struct mpoa_client *client ) ++{ ++ unsigned long flags; ++ in_cache_entry *entry; ++ ++ read_lock_irqsave(&client->ingress_lock, flags); ++ entry = client->in_cache; ++ while(entry != NULL){ ++ if(entry->shortcut == vcc) { ++ read_unlock_irqrestore(&client->ingress_lock, flags); ++ return entry; ++ } ++ entry = entry->next; ++ } ++ read_unlock_irqrestore(&client->ingress_lock, flags); ++ ++ return NULL; ++} ++ ++static in_cache_entry *new_in_cache_entry(uint32_t dst_ip, ++ struct mpoa_client *client) ++{ ++ unsigned long flags; ++ unsigned char *ip = (unsigned char *)&dst_ip; ++ in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL); ++ ++ if (entry == NULL) { ++ printk("mpoa: mpoa_caches.c: new_in_cache_entry() out of memory\n"); ++ return NULL; ++ } ++ ++ printk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]); ++ memset(entry,0,sizeof(in_cache_entry)); ++ ++ dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n"); ++ write_lock_irqsave(&client->ingress_lock, flags); ++ entry->next = client->in_cache; ++ entry->prev = NULL; ++ if (client->in_cache != NULL) ++ client->in_cache->prev = entry; ++ client->in_cache = entry; ++ write_unlock_irqrestore(&client->ingress_lock, flags); ++ dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlocked\n"); ++ ++ memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); ++ entry->ctrl_info.in_dst_ip = dst_ip; ++ do_gettimeofday(&(entry->tv)); ++ entry->retry_time = MPC_P4; ++ entry->count = 1; ++ entry->entry_state = INGRESS_INVALID; ++ entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT; ++ ++ return entry; ++} ++ ++static int cache_hit( in_cache_entry * entry, struct mpoa_client *mpc) ++{ ++ struct k_message msg; ++ ++ entry->count++; ++ if(entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL) ++ return OPEN; ++ ++ if(entry->entry_state == INGRESS_REFRESHING){ ++ if(entry->count > MPC_P1){ ++ msg.type = SND_MPOA_RES_RTRY; ++ msg.content.in_info = entry->ctrl_info; ++ memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); ++ msg_to_mpoad(&msg, mpc); ++ do_gettimeofday(&(entry->reply_wait)); ++ entry->entry_state = INGRESS_RESOLVING; ++ } ++ if(entry->shortcut != NULL) ++ return OPEN; ++ return CLOSED; ++ } ++ ++ if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) ++ return OPEN; ++ ++ if( entry->count > MPC_P1 && ++ entry->entry_state == INGRESS_INVALID){ ++ unsigned char *ip = (unsigned char *)&entry->ctrl_info.in_dst_ip; ++ ++ printk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); ++ entry->entry_state = INGRESS_RESOLVING; ++ msg.type = SND_MPOA_RES_RQST; ++ memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN ); ++ msg.content.in_info = entry->ctrl_info; ++ msg_to_mpoad( &msg, mpc); ++ do_gettimeofday(&(entry->reply_wait)); ++ } ++ ++ return CLOSED; ++} ++ ++/* ++ * If there are no more references to vcc in egress cache, ++ * we are ready to close it. ++ */ ++static void close_unused_egress_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc) ++{ ++ if (vcc == NULL) ++ return; ++ ++ printk("mpoa: mpoa_caches.c: close_unused_egress_vcc:\n"); ++ if (mpc->eg_ops->search_by_vcc(vcc, mpc) != NULL) ++ return; /* entry still in use */ ++ ++ atm_async_release_vcc(vcc, -EPIPE); /* nobody uses this VCC anymore, close it */ ++ printk("mpoa: mpoa_caches.c: close_unused_egress_vcc, closed one:\n"); ++ ++ return; ++} ++ ++/* ++ * This should be called with write lock on ++ */ ++static int in_cache_remove( in_cache_entry *entry, ++ struct mpoa_client *client ) ++{ ++ struct atm_vcc *vcc; ++ struct k_message msg; ++ unsigned char *ip; ++ ++ if(entry == NULL) ++ return 0; ++ ++ vcc = entry->shortcut; ++ ip = (unsigned char *)&entry->ctrl_info.in_dst_ip; ++ printk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",ip[0], ip[1], ip[2], ip[3]); ++ ++ if (entry->prev != NULL) ++ entry->prev->next = entry->next; ++ else ++ client->in_cache = entry->next; ++ if (entry->next != NULL) ++ entry->next->prev = entry->prev; ++ memset(entry, 0, sizeof(in_cache_entry)); ++ kfree(entry); ++ if(client->in_cache == NULL && client->eg_cache == NULL){ ++ msg.type = STOP_KEEP_ALIVE_SM; ++ msg_to_mpoad(&msg,client); ++ } ++ ++ close_unused_egress_vcc(vcc, client); ++ return 1; ++} ++ ++ ++/* Call this every MPC-p2 seconds... Not exactly correct solution, ++ but an easy one... */ ++ ++static void clear_count_and_expired(struct mpoa_client *client) ++{ ++ unsigned char *ip; ++ unsigned long flags; ++ in_cache_entry *entry, *next_entry; ++ struct timeval now; ++ ++ do_gettimeofday(&now); ++ ++ write_lock_irqsave(&client->ingress_lock, flags); ++ entry = client->in_cache; ++ while(entry != NULL){ ++ entry->count=0; ++ next_entry = entry->next; ++ if((now.tv_sec - entry->tv.tv_sec) ++ > entry->ctrl_info.holding_time){ ++ ip = (unsigned char*)&entry->ctrl_info.in_dst_ip; ++ printk("mpoa: mpoa_caches.c: holding time expired, ip = %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); ++ in_cache_remove(entry, client); ++ } ++ entry = next_entry; ++ } ++ write_unlock_irqrestore(&client->ingress_lock, flags); ++ ++ return; ++} ++ ++/* Call this every MPC-p4 seconds. */ ++ ++static void check_resolving_entries( struct mpoa_client * client ) ++{ ++ ++ unsigned long flags; ++ in_cache_entry *entry; ++ struct timeval now; ++ struct k_message msg; ++ ++ do_gettimeofday( &now ); ++ ++ read_lock_irqsave(&client->ingress_lock, flags); ++ entry = client->in_cache; ++ while( entry != NULL ){ ++ if(entry->entry_state == INGRESS_RESOLVING){ ++ if(now.tv_sec - entry->hold_down.tv_sec < MPC_P6){ ++ entry = entry->next; /* Entry in hold down */ ++ continue; ++ } ++ if( (now.tv_sec - entry->reply_wait.tv_sec) > ++ entry->retry_time ){ ++ entry->retry_time = MPC_C1*( entry->retry_time ); ++ if(entry->retry_time > MPC_P5){ ++ /* Retry time maximum exceeded, put entry in hold down. */ ++ do_gettimeofday(&(entry->hold_down)); ++ entry->retry_time = MPC_P4; ++ entry = entry->next; ++ continue; ++ } ++ /* Ask daemon to send a resolution request. */ ++ memset(&(entry->hold_down),0,sizeof(struct timeval)); ++ msg.type = SND_MPOA_RES_RTRY; ++ memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); ++ msg.content.in_info = entry->ctrl_info; ++ msg_to_mpoad(&msg, client ); ++ do_gettimeofday(&(entry->reply_wait)); ++ } ++ } ++ entry = entry->next; ++ } ++ read_unlock_irqrestore(&client->ingress_lock, flags); ++} ++ ++/* Call this every MPC-p5 seconds. */ ++ ++static void refresh_entries( struct mpoa_client * client ) ++{ ++ unsigned long flags; ++ struct timeval now; ++ struct in_cache_entry *entry = client->in_cache; ++ ++ ddprintk("mpoa: mpoa_caches.c: refresh_entries\n"); ++ do_gettimeofday(&now); ++ ++ read_lock_irqsave(&client->ingress_lock, flags); ++ while( entry != NULL ){ ++ if( entry->entry_state == INGRESS_RESOLVED ){ ++ if(!(entry->refresh_time)) ++ entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3; ++ if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){ ++ dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n"); ++ entry->entry_state = INGRESS_REFRESHING; ++ ++ } ++ } ++ entry = entry->next; ++ } ++ read_unlock_irqrestore(&client->ingress_lock, flags); ++} ++ ++static eg_cache_entry *eg_cache_search_by_cache_id(uint32_t cache_id, ++ struct mpoa_client *client) ++{ ++ eg_cache_entry *entry; ++ unsigned long flags; ++ ++ read_lock_irqsave(&client->egress_lock, flags); ++ entry = client->eg_cache; ++ while(entry != NULL){ ++ if( entry->ctrl_info.cache_id == cache_id){ ++ read_unlock_irqrestore(&client->egress_lock, flags); ++ return entry; ++ } ++ entry = entry->next; ++ } ++ read_unlock_irqrestore(&client->egress_lock, flags); ++ ++ return NULL; ++} ++ ++static eg_cache_entry *eg_cache_search_by_tag(uint32_t tag, ++ struct mpoa_client *client) ++{ ++ unsigned long flags; ++ eg_cache_entry *entry; ++ ++ read_lock_irqsave(&client->egress_lock, flags); ++ entry = client->eg_cache; ++ while(entry != NULL){ ++ if( entry->ctrl_info.tag == tag){ ++ read_unlock_irqrestore(&client->egress_lock, flags); ++ return entry; ++ } ++ entry = entry->next; ++ } ++ read_unlock_irqrestore(&client->egress_lock, flags); ++ ++ return NULL; ++} ++ ++static eg_cache_entry *eg_cache_search_by_vcc(struct atm_vcc *vcc, ++ struct mpoa_client *client ) ++{ ++ unsigned long flags; ++ eg_cache_entry *entry; ++ ++ read_lock_irqsave(&client->egress_lock, flags); ++ entry = client->eg_cache; ++ while( entry != NULL ){ ++ if( entry->shortcut == vcc ) { ++ read_unlock_irqrestore(&client->egress_lock, flags); ++ return entry; ++ } ++ entry = entry->next; ++ } ++ read_unlock_irqrestore(&client->egress_lock, flags); ++ ++ return NULL; ++} ++ ++/* ++ * If there are no more references to vcc in ingress cache, ++ * we are ready to close it. ++ */ ++static void close_unused_ingress_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc) ++{ ++ if (vcc == NULL) ++ return; ++ ++ printk("mpoa: mpoa_caches.c: close_unused_ingress_vcc:\n"); ++ if (mpc->in_ops->search_by_vcc(vcc, mpc) != NULL) ++ return; /* entry still in use */ ++ ++ atm_async_release_vcc(vcc, -EPIPE); /* nobody uses this VCC anymore, close it */ ++ printk("mpoa: mpoa_caches.c: close_unused_ingress_vcc:, closed one\n"); ++ ++ return; ++} ++/* ++ * This should be called with write lock on ++ */ ++static int eg_cache_remove(eg_cache_entry *entry, ++ struct mpoa_client *client) ++{ ++ struct atm_vcc *vcc; ++ struct k_message msg; ++ if(entry == NULL) ++ return 0; ++ ++ vcc = entry->shortcut; ++ printk("mpoa: mpoa_caches.c: removing an egress entry.\n"); ++ if (entry->prev != NULL) ++ entry->prev->next = entry->next; ++ else ++ client->eg_cache = entry->next; ++ if (entry->next != NULL) ++ entry->next->prev = entry->prev; ++ memset(entry, 0, sizeof(eg_cache_entry)); ++ kfree(entry); ++ if(client->in_cache == NULL && client->eg_cache == NULL){ ++ msg.type = STOP_KEEP_ALIVE_SM; ++ msg_to_mpoad(&msg,client); ++ } ++ ++ close_unused_ingress_vcc(vcc, client); ++ ++ return 1; ++} ++ ++static eg_cache_entry *new_eg_cache_entry(struct k_message *msg, struct mpoa_client *client) ++{ ++ unsigned long flags; ++ unsigned char *ip; ++ eg_cache_entry *entry = kmalloc(sizeof(eg_cache_entry), GFP_KERNEL); ++ ++ if (entry == NULL) { ++ printk("mpoa: mpoa_caches.c: new_eg_cache_entry() out of memory\n"); ++ return NULL; ++ } ++ ++ ip = (unsigned char *)&msg->content.eg_info.eg_dst_ip; ++ printk("mpoa: mpoa_caches.c: adding an egress entry, ip = %d.%d.%d.%d, this should be our IP\n", ip[0], ip[1], ip[2], ip[3]); ++ memset(entry, 0, sizeof(eg_cache_entry)); ++ ++ dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n"); ++ write_lock_irqsave(&client->egress_lock, flags); ++ entry->next = client->eg_cache; ++ entry->prev = NULL; ++ if (client->eg_cache != NULL) ++ client->eg_cache->prev = entry; ++ client->eg_cache = entry; ++ write_unlock_irqrestore(&client->egress_lock, flags); ++ dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n"); ++ ++ memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); ++ entry->ctrl_info = msg->content.eg_info; ++ do_gettimeofday(&(entry->tv)); ++ entry->entry_state = EGRESS_RESOLVED; ++ printk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id)); ++ ip = (unsigned char *)&entry->ctrl_info.mps_ip; ++ printk("mpoa: mpoa_caches.c: mps_ip = %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); ++ return entry; ++} ++ ++static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time) ++{ ++ do_gettimeofday(&(entry->tv)); ++ entry->entry_state = EGRESS_RESOLVED; ++ entry->ctrl_info.holding_time = holding_time; ++ ++ return; ++} ++ ++static void clear_expired(struct mpoa_client *client){ ++ eg_cache_entry *entry, *next_entry; ++ unsigned long flags; ++ struct timeval now; ++ struct k_message msg; ++ ++ do_gettimeofday(&now); ++ ++ write_lock_irqsave(&client->egress_lock, flags); ++ entry = client->eg_cache; ++ while(entry != NULL){ ++ next_entry = entry->next; ++ if((now.tv_sec - entry->tv.tv_sec) ++ > entry->ctrl_info.holding_time){ ++ msg.type = SND_EGRESS_PURGE; ++ msg.content.eg_info = entry->ctrl_info; ++ printk("mpoa: mpoa_caches.c: egress_cache:holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id)); ++ msg_to_mpoad(&msg,client); ++ eg_cache_remove(entry, client); ++ } ++ entry = next_entry; ++ } ++ write_unlock_irqrestore(&client->egress_lock, flags); ++ ++ return; ++} ++ ++ ++ ++static struct in_cache_ops ingress_ops = { ++ new_in_cache_entry, /* new_entry */ ++ in_cache_search, /* search */ ++ in_cache_search_by_vcc, /* search_by_vcc */ ++ cache_hit, /* cache_hit */ ++ in_cache_remove, /* cache_remove */ ++ clear_count_and_expired, /* clear_count */ ++ check_resolving_entries, /* check_resolving */ ++ refresh_entries /* refresh */ ++}; ++ ++static struct eg_cache_ops egress_ops = { ++ new_eg_cache_entry, /* new_entry */ ++ eg_cache_search_by_cache_id, /* search_by_cache_id */ ++ eg_cache_search_by_tag, /* search_by_tag */ ++ eg_cache_search_by_vcc, /* search_by_vcc */ ++ eg_cache_remove, /* cache_remove */ ++ update_eg_cache_entry, /* update */ ++ clear_expired /* clear_expired */ ++}; ++ ++ ++void atm_mpoa_init_cache(struct mpoa_client *mpc) ++{ ++ mpc->in_ops = &ingress_ops; ++ mpc->eg_ops = &egress_ops; ++ ++ return; ++} +--- /dev/null Tue Jan 1 05:00:00 1980 ++++ work/net/atm/mpoa_caches.h Tue Aug 11 19:14:28 1998 +@@ -0,0 +1,87 @@ ++#ifndef MPOA_CACHES_H ++#define MPOA_CACHES_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++ ++struct mpoa_client; ++ ++void atm_mpoa_init_cache(struct mpoa_client *mpc); ++ ++typedef struct in_cache_entry { ++ struct in_cache_entry *next; ++ struct in_cache_entry *prev; ++ struct timeval tv; ++ struct timeval reply_wait; ++ struct timeval hold_down; ++ uint32_t packets_fwded; ++ uint16_t entry_state; ++ uint32_t retry_time; ++ uint32_t refresh_time; ++ uint32_t count; ++ struct atm_vcc *shortcut; ++ uint8_t MPS_ctrl_ATM_addr[ATM_ESA_LEN]; ++ struct in_ctrl_info ctrl_info; ++} in_cache_entry; ++ ++struct in_cache_ops{ ++ in_cache_entry *(*new_entry)(uint32_t dst_ip, ++ struct mpoa_client *client); ++ in_cache_entry *(*search)(uint32_t dst_ip, struct mpoa_client *client); ++ in_cache_entry *(*search_by_vcc)(struct atm_vcc *vcc, ++ struct mpoa_client *client); ++ int (*cache_hit)(in_cache_entry *entry, ++ struct mpoa_client *client); ++ int (*cache_remove)(in_cache_entry *delEntry, ++ struct mpoa_client *client ); ++ void (*clear_count)(struct mpoa_client *client); ++ void (*check_resolving)(struct mpoa_client *client); ++ void (*refresh)(struct mpoa_client *client); ++}; ++ ++typedef struct eg_cache_entry{ ++ struct eg_cache_entry *next; ++ struct eg_cache_entry *prev; ++ struct timeval tv; ++ uint8_t MPS_ctrl_ATM_addr[ATM_ESA_LEN]; ++ struct atm_vcc *shortcut; ++ uint32_t packets_rcvd; ++ uint16_t entry_state; ++ struct eg_ctrl_info ctrl_info; ++} eg_cache_entry; ++ ++struct eg_cache_ops{ ++ eg_cache_entry *(*new_entry)(struct k_message *msg, struct mpoa_client *client); ++ eg_cache_entry *(*search_by_cache_id)(uint32_t cache_id, struct mpoa_client *client); ++ eg_cache_entry *(*search_by_tag)(uint32_t cache_id, struct mpoa_client *client); ++ eg_cache_entry *(*search_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client); ++ int (*cache_remove)(eg_cache_entry *entry, struct mpoa_client *client); ++ void (*update)(eg_cache_entry *entry, uint16_t holding_time); ++ void (*clear_expired)(struct mpoa_client *client); ++}; ++ ++ ++/* Ingress cache entry states */ ++ ++#define INGRESS_REFRESHING 3 ++#define INGRESS_RESOLVED 2 ++#define INGRESS_RESOLVING 1 ++#define INGRESS_INVALID 0 ++ ++/* VCC states */ ++ ++#define OPEN 1 ++#define CLOSED 0 ++ ++/* Egress cache entry states */ ++ ++#define EGRESS_RESOLVED 2 ++#define EGRESS_PURGE 1 ++#define EGRESS_INVALID 0 ++ ++#endif +--- /dev/null Tue Jan 1 05:00:00 1980 ++++ work/net/atm/mpoa_proc.c Tue Aug 11 19:14:28 1998 +@@ -0,0 +1,246 @@ ++#include ++ ++#ifdef CONFIG_PROC_FS ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mpc.h" ++#include "mpoa_caches.h" ++ ++/* ++ * mpoa_proc.c: Implementation MPOA client's proc ++ * file system statistics ++ */ ++ ++extern struct mpoa_client *mpcs; ++ ++static ssize_t proc_mpc_read(struct file *file, char *buff, ++ size_t count, loff_t *pos); ++ ++/* ++ * /proc/mpoa DIRECTORY ENTRY. ++ */ ++static struct proc_dir_entry mpc_proc_root = { ++ 0, /* low_ino (0=dynamic?) */ ++ 4, /* name length */ ++ "mpoa", /* name string */ ++ S_IFDIR | S_IRUGO | S_IXUGO, /* mode/permissions */ ++ 2, /* 2=dir */ ++ 0, /* UID */ ++ 0, /* GID */ ++ 0, /* size */ ++ &proc_dir_inode_operations, /* inode operations */ ++ NULL, /* get_info func-ptr */ ++ NULL, /* fill_inode func-ptr */ ++ NULL, /* next ptr */ ++ NULL, /* parent ptr */ ++ NULL /* subdir ptr */ ++}; ++ ++/* ++ * Define allowed FILE OPERATIONS ++ */ ++static struct file_operations mpc_file_operations = { ++ NULL, /* lseek */ ++ proc_mpc_read, /* read */ ++ NULL, /* write */ ++ NULL, /* readdir */ ++ NULL, /* poll - default */ ++ NULL, /* ioctl - default */ ++ NULL, /* mmap */ ++ NULL, /* no special open code */ ++ NULL, /* no special release code */ ++ NULL /* no fsync */ ++}; ++ ++/* ++ * Define allowed INODE OPERATIONS ++ */ ++static struct inode_operations mpc_inode_operations = { ++ &mpc_file_operations, ++ NULL, /* create */ ++ NULL, /* lookup */ ++ NULL, /* link */ ++ NULL, /* unlink */ ++ NULL, /* symlink */ ++ NULL, /* mkdir */ ++ NULL, /* rmdir */ ++ NULL, /* mknod */ ++ NULL, /* rename */ ++ NULL, /* readlink */ ++ NULL, /* follow_link */ ++ NULL, /* readpage */ ++ NULL, /* writepage */ ++ NULL, /* bmap */ ++ NULL, /* truncate */ ++ NULL /* permission */ ++}; ++ ++/* ++ * /proc/mpoa/mpc_stats REGULAR_FILE ++ */ ++static struct proc_dir_entry mpc_stats = { ++ 0, /* low_ino */ ++ 9, /* name length */ ++ "mpc_stats", /* name */ ++ S_IFREG | S_IRUGO, /* mode */ ++ 1, /* 1=file */ ++ 0, /* UID */ ++ 0, /* GID */ ++ 0, /* size */ ++ &mpc_inode_operations, /* inode operations */ ++ NULL /* get_info func-ptr */ ++ ++}; ++ ++static int print_header(char *buff,struct mpoa_client *mpc){ ++ if(mpc != NULL){ ++ return sprintf(buff,"\nInterface %d:\n\n",mpc->dev_num); ++ ++ } ++ return 0; ++} ++ ++/* ++ * Returns the state of an ingress cache entry as a string ++ */ ++static const char *ingress_state_string(int state){ ++ switch(state) { ++ case INGRESS_RESOLVING: ++ return "resolving "; ++ break; ++ case INGRESS_RESOLVED: ++ return "resolved "; ++ break; ++ case INGRESS_INVALID: ++ return "invalid "; ++ break; ++ case INGRESS_REFRESHING: ++ return "refreshing "; ++ break; ++ default: ++ return ""; ++ } ++} ++ ++/* ++ * Returns the state of an egress cache entry as a string ++ */ ++static const char *egress_state_string(int state){ ++ switch(state) { ++ case EGRESS_RESOLVED: ++ return "resolved "; ++ break; ++ case EGRESS_PURGE: ++ return "purge "; ++ break; ++ case EGRESS_INVALID: ++ return "invalid "; ++ break; ++ default: ++ return ""; ++ } ++} ++ ++/* ++ * READING function - called when the /proc/atm/mpoa file is read from. ++ */ ++static ssize_t proc_mpc_read(struct file *file, char *buff, ++ size_t count, loff_t *pos){ ++ unsigned long page = 0; ++ unsigned char *temp; ++ ssize_t length = 0; ++ int i = 0; ++ struct mpoa_client *mpc = mpcs; ++ in_cache_entry *in_entry; ++ eg_cache_entry *eg_entry; ++ struct timeval now; ++ unsigned char ip_string[16]; ++ if(count < 0) ++ return -EINVAL; ++ if(count == 0) ++ return 0; ++ page = get_free_page(GFP_KERNEL); ++ if(!page) ++ return -ENOMEM; ++ while(mpc != NULL){ ++ length += print_header((char *)page + length, mpc); ++ length += sprintf((char *)page + length,"Ingress Entries:\nIP-address State Holding_time Packets_fwded VPI VCI\n"); ++ in_entry = mpc->in_cache; ++ do_gettimeofday(&now); ++ while(in_entry != NULL){ ++ temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); ++ length += sprintf((char *)page + length,"%-16s%s%-14lu%-12u", ip_string, ingress_state_string(in_entry->entry_state), (in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec)), in_entry->packets_fwded); ++ if(in_entry->shortcut) ++ length += sprintf((char *)page + length," %-3d %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci); ++ length += sprintf((char *)page + length,"\n"); ++ in_entry = in_entry->next; ++ } ++ length += sprintf((char *)page + length,"\n"); ++ eg_entry = mpc->eg_cache; ++ length += sprintf((char *)page + length,"Egress Entries:\nIngress_MPC_ATM_addr\nCache_id State Holding_time Packets_recvd VPI VCI\n"); ++ while(eg_entry != NULL){ ++ for(i=0;ictrl_info.in_MPC_data_ATM_addr[i]);} ++ length += sprintf((char *)page + length,"\n%-16lu%s%-14lu%-12u",ntohl(eg_entry->ctrl_info.cache_id), egress_state_string(eg_entry->entry_state), (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), eg_entry->packets_rcvd); ++ if(eg_entry->shortcut) ++ length += sprintf((char *)page + length," %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci); ++ length += sprintf((char *)page + length,"\n"); ++ eg_entry = eg_entry->next; ++ } ++ length += sprintf((char *)page + length,"\n"); ++ mpc = mpc->next; ++ } ++ ++ if (*pos >= length) length = 0; ++ else { ++ if ((count + *pos) > length) count = length - *pos; ++ copy_to_user(buff, (char *)page , count); ++ *pos += count; ++ } ++ ++ free_page(page); ++ return length; ++} ++ ++/* ++ * INITIALIZATION function - called when module is initialized/loaded. ++ */ ++int mpc_proc_init(void) ++{ ++ int retval = 0; ++ ++ if ( (retval = proc_register(&proc_root,&mpc_proc_root)) != 0 ) { ++ printk(KERN_ERR "Unable to initialize /proc/mpoa/\n"); ++ return retval; ++ } ++ ++ if ( (retval = proc_register(&mpc_proc_root,&mpc_stats)) != 0 ) { ++ printk(KERN_ERR "Unable to initialize /proc/mpoa/mpc_stats\n"); ++ return retval; ++ } ++ return 0; ++} ++ ++/* ++ * DELETING function - called when module is removed. ++ */ ++void mpc_proc_clean(void) ++{ ++ proc_unregister(&mpc_proc_root,mpc_stats.low_ino); ++ proc_unregister(&proc_root,mpc_proc_root.low_ino); ++} ++ ++ ++#endif /* CONFIG_PROC_FS */ ++ ++ ++ ++ ++ ++ +--- /dev/null Tue Jan 1 05:00:00 1980 ++++ work/net/atm/lane_mpoa_init.c Tue Aug 11 19:14:28 1998 +@@ -0,0 +1,44 @@ ++#include ++#include ++ ++#include "mpc.h" ++#include "lec.h" ++ ++/* ++ * lane_mpoa_init.c: A couple of helper functions ++ * to make modular LANE and MPOA client easier to implement ++ */ ++ ++/* ++ * This is how it goes: ++ * ++ * if xxxx is not compiled as module, call atm_xxxx_init_ops() ++ * from here ++ * else call atm_mpoa_init_ops() from init_module() within ++ * the kernel when xxxx module is loaded ++ * ++ * In either case function pointers in struct atm_xxxx_ops ++ * are initialized to their correct values. Either they ++ * point to functions in the module or in the kernel ++ */ ++ ++extern struct atm_mpoa_ops atm_mpoa_ops; /* in common.c */ ++extern struct atm_lane_ops atm_lane_ops; /* in common.c */ ++ ++void atm_mpoa_init(void) ++{ ++#ifndef CONFIG_ATM_MPOA_MODULE /* not module */ ++ atm_mpoa_init_ops(&atm_mpoa_ops); ++#endif ++ ++ return; ++} ++ ++void atm_lane_init(void) ++{ ++#ifndef CONFIG_ATM_LANE_MODULE /* not module */ ++ atm_lane_init_ops(&atm_lane_ops); ++#endif ++ ++ return; ++} +--- /dev/null Tue Jan 1 05:00:00 1980 ++++ work/net/atm/proc.c Tue Aug 11 20:42:50 1998 +@@ -0,0 +1,610 @@ ++/* net/atm/proc.c - ATM /proc interface */ ++ ++/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ ++ ++/* ++ * The mechanism used here isn't designed for speed but rather for convenience ++ * of implementation. We only return one entry per read system call, so we can ++ * be reasonably sure not to overrun the page and race conditions may lead to ++ * the addition or omission of some lines but never to any corruption of a ++ * line's internal structure. ++ * ++ * Making the whole thing slightly more efficient is left as an exercise to the ++ * reader. (Suggestions: wrapper which loops to get several entries per system ++ * call; or make --left slightly more clever to avoid O(n^2) characteristics.) ++ * I find it fast enough on my unloaded 266 MHz Pentium 2 :-) ++ */ ++ ++ ++#include ++#include /* for EXPORT_SYMBOL */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* for __initfunc */ ++#include ++#include /* for HZ */ ++#include "resources.h" ++#include "common.h" /* atm_proc_init prototype */ ++#include "signaling.h" /* to get sigd - ugly too */ ++ ++#ifdef CONFIG_AREQUIPA ++#include ++void atm_push_arequipa(struct atm_vcc *vcc,struct sk_buff *skb); ++#endif ++ ++#ifdef CONFIG_ATM_CLIP ++#include ++#include "ipcommon.h" ++extern void clip_push(struct atm_vcc *vcc,struct sk_buff *skb); ++#endif ++ ++#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) ++#include "lec.h" ++#include "lec_arpc.h" ++extern struct atm_lane_ops atm_lane_ops; /* in common.c */ ++#endif ++ ++ ++static ssize_t proc_atm_read(struct file *file,char *buf,size_t count, ++ loff_t *pos); ++ ++ ++static struct file_operations proc_atm_operations = { ++ NULL, /* lseek */ ++ proc_atm_read, /* read */ ++ NULL, /* write */ ++ NULL, /* readdir */ ++ NULL, /* select */ ++ NULL, /* ioctl */ ++ NULL, /* mmap */ ++ NULL, /* no special open code */ ++ NULL, /* no special release */ ++ NULL /* can't fsync */ ++}; ++ ++struct inode_operations proc_atm_inode_operations = { ++ &proc_atm_operations, /* default ATM directory file-ops */ ++ NULL, /* create */ ++ NULL, /* lookup */ ++ NULL, /* link */ ++ NULL, /* unlink */ ++ NULL, /* symlink */ ++ NULL, /* mkdir */ ++ NULL, /* rmdir */ ++ NULL, /* mknod */ ++ NULL, /* rename */ ++ NULL, /* readlink */ ++ NULL, /* follow_link */ ++ NULL, /* readpage */ ++ NULL, /* writepage */ ++ NULL, /* bmap */ ++ NULL, /* truncate */ ++ NULL /* permission */ ++}; ++ ++ ++#define ENTRY(name) static struct proc_dir_entry atm_proc_entry_##name = \ ++ { 0, sizeof(#name)-1, #name, S_IFREG | S_IRUGO, 1, 0, 0, 0, \ ++ &proc_atm_inode_operations, NULL } ++#define REG(name) if (!error) error = proc_register(&atm_proc_root, \ ++ &atm_proc_entry_##name) ++#define INO(name) (atm_proc_entry_##name.low_ino) ++ ++ ++ENTRY(devices); ++ENTRY(pvc); ++ENTRY(svc); ++#ifdef CONFIG_ATM_CLIP ++ENTRY(arp); ++#endif ++#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) ++ENTRY(lec); ++#endif ++#ifdef CONFIG_AREQUIPA ++ENTRY(arequipa); ++#endif ++ ++ ++static int atm_header(ino_t ino,char *buf) ++{ ++ if (ino == INO(devices)) ++ return sprintf(buf,"Itf Type ESI/\"MAC\"addr " + "AAL(TX,err,RX,err,drop) ...\n"); + if (ino == INO(pvc)) + return sprintf(buf,"Itf VPI VCI AAL RX(PCR,Class) " @@ -13119,10 +15585,10 @@ + int i, count, d, e; + struct device **dev_lec; + -+ if (ptr_to_get_dev_lec == NULL) ++ if (atm_lane_ops.get_lecs == NULL) + return 0; /* the lane module is not there yet */ + else -+ dev_lec = ptr_to_get_dev_lec(); ++ dev_lec = atm_lane_ops.get_lecs(); + + count = *pos; + for(d=0;d ++ ++extern struct proc_dir_entry atm_proc_root; /* @@@ move elsewhere */ ++ +int atm_proc_dev_register(struct atm_dev *dev); +void atm_proc_dev_deregister(struct atm_dev *dev); ++ +#endif + +#endif @@ -13983,7 +16459,7 @@ + return 0; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/signaling.h Tue Aug 4 17:58:20 1998 ++++ work/net/atm/signaling.h Tue Aug 11 19:46:26 1998 @@ -0,0 +1,25 @@ +/* net/atm/signaling.h - ATM signaling */ + @@ -14011,8 +16487,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/svc.c Thu Jun 18 10:14:09 1998 -@@ -0,0 +1,385 @@ ++++ work/net/atm/svc.c Tue Aug 11 19:54:16 1998 +@@ -0,0 +1,387 @@ +/* net/atm/svc.c - ATM SVC sockets */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -14252,6 +16728,8 @@ + while (1) { + while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) { + if (old_vcc->flags & ATM_VF_RELEASED) break; ++ if (old_vcc->flags & ATM_VF_CLOSE) ++ return old_vcc->reply; + if (flags & O_NONBLOCK) return -EAGAIN; + interruptible_sleep_on(&old_vcc->sleep); + if (signal_pending(current)) return -ERESTARTSYS; diff -ur --new-file old/atm/doc/usage.tex new/atm/doc/usage.tex --- old/atm/doc/usage.tex Tue Aug 4 19:18:10 1998 +++ new/atm/doc/usage.tex Wed Aug 12 19:41:18 1998 @@ -1,7 +1,7 @@ %%def%:= %:\begin{verbatim} -%:Usage instructions - ATM on Linux, release 0.39 +%:Usage instructions - ATM on Linux, release 0.40 %:------------------------------------------------- %: %:\end{verbatim} @@ -38,14 +38,14 @@ \title{ATM on Linux \\ User's guide \\ - Release 0.39 (alpha)} + Release 0.40 (alpha)} \author{Werner Almesberger \\ {\tt Werner.Almesberger@epfl.ch} \\ \\ Institute for computer Communications and Applications (ICA) \\ EPFL, CH-1015 Lausanne, Switzerland} -\date{August 4, 1998} +\date{August 12, 1998} \begin{document} \maketitle @@ -81,7 +81,7 @@ In order to install this package, you need \begin{itemize} \item the package itself - \url{ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.39.tar.gz} + \url{ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.40.tar.gz} \item the Linux kernel, version 2.1.105, e.g. from \url{ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.1.105.tar.gz} \item Perl, version 4 or 5 @@ -98,7 +98,7 @@ distribution: \begin{verbatim} -tar xfz atm-0.39.tar.gz +tar xfz atm-0.40.tar.gz \end{verbatim} and the kernel source: @@ -131,9 +131,10 @@ \name{aread}, \name{awrite}, \name{br}, \name{bw}, \name{isp}, \name{ttcp\_atm}, \name{window} \item[\path{atm/arpd/}] ATMARP tools and demon: \name{atmarp}, \name{atmarpd} - \item[\path{atm/led/}] LAN Emulation demon: \name{led} + \item[\path{atm/led/}] LAN Emulation demon: \name{zeppelin} \item[\path{atm/lane/}] LAN Emulation servers: \name{bus}, \name{lecs}, \name{les} + \item[\path{atm/mpoad/}] Multi-Protocol Over ATM demon: \name{mpcd} \item[\path{atm/aqd/}] Arequipa demon: \name{aqpvc}, \name{arequipad} \item[\path{atm/debug/}] Debugging tools: \name{aqtest}, \name{delay}, \name{ed}, \name{encopy}, \name{endump}, \name{svctor}, \name{zndump}, diff -ur --new-file old/atm/doc/usage.txt new/atm/doc/usage.txt --- old/atm/doc/usage.txt Tue Aug 4 21:15:42 1998 +++ new/atm/doc/usage.txt Thu Aug 13 13:38:23 1998 @@ -1,4 +1,4 @@ -Usage instructions - ATM on Linux, release 0.39 +Usage instructions - ATM on Linux, release 0.40 ------------------------------------------------- For updates of ATM on Linux, please check the Web page at @@ -17,7 +17,7 @@ In order to install this package, you need - the package itself - ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.39.tar.gz + ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.40.tar.gz - the Linux kernel, version 2.1.105, e.g. from ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.1.105.tar.gz - Perl, version 4 or 5 @@ -33,7 +33,7 @@ all the files listed above there. Then extract the ATM on Linux distribution: -tar xfz atm-0.39.tar.gz +tar xfz atm-0.40.tar.gz and the kernel source: @@ -57,8 +57,9 @@ atm/test/ Test programs: align, aping, aread, awrite, br, bw, isp, ttcp_atm, window atm/arpd/ ATMARP tools and demon: atmarp, atmarpd - atm/led/ LAN Emulation demon: led + atm/led/ LAN Emulation demon: zeppelin atm/lane/ LAN Emulation servers: bus, lecs, les + atm/mpoad/ Multi-Protocol Over ATM demon: mpcd atm/aqd/ Arequipa demon: aqpvc, arequipad atm/debug/ Debugging tools: aqtest, delay, ed, encopy, endump, svctor, zndump, and znth diff -ur --new-file old/atm/extra/tc/q_atm.c new/atm/extra/tc/q_atm.c --- old/atm/extra/tc/q_atm.c Thu Jul 23 23:14:49 1998 +++ new/atm/extra/tc/q_atm.c Thu Aug 13 13:35:14 1998 @@ -20,8 +20,11 @@ #include "tc_util.h" +#define MAX_HDR_LEN 64 + #define usage() return(-1) + static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { if (argc) { @@ -35,7 +38,7 @@ static void explain(void) { fprintf(stderr, "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) " - "[ qos QOS ]\n"); + "[ qos QOS ] [ hdr HEX... ]\n"); } @@ -45,6 +48,9 @@ struct sockaddr_atmsvc addr; struct atm_qos qos; struct atm_sap sap; + unsigned char hdr[MAX_HDR_LEN]; + struct rtattr *tail; + int hdr_len = -1; int s; memset(&addr,0,sizeof(addr)); @@ -82,6 +88,29 @@ return -1; } } + else if (!strcmp(*argv,"hdr")) { + unsigned char *ptr; + char *walk; + + NEXT_ARG(); + ptr = hdr; + for (walk = *argv; *walk; walk += 2) { + int tmp; + + if (ptr == hdr+MAX_HDR_LEN) { + fprintf(stderr,"header is too long\n"); + return -1; + } + if (!isxdigit(walk[0]) || !walk[1] || + !isxdigit(walk[1])) { + explain(); + return -1; + } + sscanf(walk,"%2x",&tmp); + *ptr++ = tmp; + } + hdr_len = ptr-hdr; + } else { explain(); return 1; @@ -108,7 +137,11 @@ perror("connect"); return -1; } - addattr_l(n, 1024, TCA_OPTIONS, &s, sizeof(s)); + tail = (struct rtattr *) (((void *) n)+NLMSG_ALIGN(n->nlmsg_len)); + addattr_l(n,1024,TCA_OPTIONS,NULL,0); + addattr_l(n,1024,TCA_ATM_FD,&s,sizeof(s)); + if (hdr_len != -1) addattr_l(n,1024,TCA_ATM_HDR,hdr,hdr_len); + tail->rta_len = (((void *) n)+NLMSG_ALIGN(n->nlmsg_len))-(void *) tail; return 0; } @@ -116,11 +149,18 @@ static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { + struct rtattr *tb[TCA_ATM_MAX+1]; char buffer[MAX_ATM_ADDR_LEN+1]; if (!opt) return 0; - if (RTA_PAYLOAD(opt) != sizeof(struct sockaddr_atmpvc)) return -EINVAL; - if (atm2text(buffer,MAX_ATM_ADDR_LEN,RTA_DATA(opt), + memset(tb, 0, sizeof(tb)); + parse_rtattr(tb, TCA_ATM_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)); + if (!tb[TCA_ATM_ADDR]) return 0; + if (RTA_PAYLOAD(tb[TCA_ATM_ADDR]) < sizeof(struct sockaddr_atmpvc)) { + fprintf(stderr,"ATM: address too short\n"); + return 0; + } + if (atm2text(buffer,MAX_ATM_ADDR_LEN,RTA_DATA(tb[TCA_ATM_ADDR]), A2T_PRETTY | A2T_NAME) < 0) fprintf(stderr,"atm2text error\n"); printf("%s",buffer); return 0; diff -ur --new-file old/atm/ilmid/atmf_uni.c new/atm/ilmid/atmf_uni.c --- old/atm/ilmid/atmf_uni.c Tue Apr 22 04:18:53 1997 +++ new/atm/ilmid/atmf_uni.c Wed Aug 5 17:29:33 1998 @@ -1,5 +1,5 @@ /* - * atmf_uni.h - ATM Forum UNI MIB + * atmf_uni.c - ATM Forum UNI MIB * * Written by Scott W. Shumate * @@ -31,7 +31,7 @@ #define INDEX_LEN 15 #define LOCALUNI '\0' #define VALID 1 -#define INVALID 0 +#define INVALID 2 AsnOid atmfPortIndex = {13, "\53\06\01\04\01\202\141\02\01\01\01\01\00"}; AsnOid atmfMyIpNmAddress = {11, "\53\06\01\04\01\202\141\02\01\02\00"}; diff -ur --new-file old/atm/led/address.c new/atm/led/address.c --- old/atm/led/address.c Sat Jun 6 02:26:24 1998 +++ new/atm/led/address.c Tue Aug 11 16:53:56 1998 @@ -41,6 +41,7 @@ #include /* Atm includes */ +#include #include #include #include diff -ur --new-file old/atm/led/af_lane.h new/atm/led/af_lane.h --- old/atm/led/af_lane.h Wed Nov 19 12:59:15 1997 +++ new/atm/led/af_lane.h Tue Aug 11 16:53:56 1998 @@ -65,6 +65,10 @@ #define LE_FLAG_REMOTE_ADDR 0x0001 #define LE_FLAG_PROXY 0x0080 #define LE_FLAG_TOPOLOGY_CHANGE 0x0100 +#define LE_FLAG_V2_CAPABLE 0x0002 /* LANE2 */ +#define LE_FLAG_SELECTIVE_MCAST 0x0004 /* LANE2 */ +#define LE_FLAG_V2_REQUIRED 0x0008 /* LANE2 */ +#define LE_FLAG_TOKEN_RING_EE 0x0200 /* LANE2 */ /* * Control Frame Status Definitions @@ -82,6 +86,7 @@ #define LE_STATUS_NO_CONFIG 20 #define LE_STATUS_LE_CONFIG_ERROR 21 #define LE_STATUS_INSUFFICIENT_INFO 22 +#define LE_STATUS_TLV_NOT_FOUND 24 /* LANE2 */ /* * Control Frame Op-Codes @@ -102,6 +107,8 @@ #define LE_FLUSH_RSP 0x0107 #define LE_NARP_REQ 0x0008 #define LE_TOPOLOGY_REQ 0x0009 +#define LE_VERIFY_REQ 0x000a /* LANE2 */ +#define LE_VERIFY_RSP 0x010a /* LANE2 */ /* * TLV Types @@ -121,6 +128,13 @@ #define TLV_MCAST_VCC_AVG_RATE 0x00a03e0d #define TLV_MCAST_VCC_PEAK_RATE 0x00a03e0e #define TLV_CONNECT_COMPLETION_TIMER 0x00a03e0f +#define TLV_X5_ADJUSTEMENT 0x00a03e2c /* LANE2 TLVs from here */ +#define TLV_L3_ADDRESS 0x00a03e11 +#define TLV_ELAN_ID 0x00a03e12 +#define TLV_PREFERRED_LES 0x00a03e2d +#define TLV_SERVICE_CATEGORY 0x00a03e13 +#define TLV_LLC_MUXED_ATM_ADDRESS 0x00a03e2b +#define TLV_CONFIG_FRAG_INFO 0x00a03e10 /* Definitions for BLLI codepoint values in signaled VCCs. */ @@ -244,10 +258,26 @@ LE_LAN_DST src_lan_dst; LE_LAN_DST target_lan_dst; ADDR_ATM src_atm_addr; - UINT32 reserved1; + /* UINT32 reserved1; */ /* lane 1 version */ + UINT16 reserved1; + UINT8 tlv_count; /* LANE2: tlv_count added */ + UINT8 reserved3; ADDR_ATM target_atm_addr; UINT32 reserved2[8]; } LE_ARP_FRAME; + +typedef struct /* this is the LANE2 version */ + { + LE_CTRL_HDR hdr; + LE_LAN_DST src_lan_dst; + LE_LAN_DST target_lan_dst; + ADDR_ATM src_atm_addr; + UINT16 reserved; + UINT8 tlv_count; + UINT8 reserved2; + ADDR_ATM target_atm_addr; + UINT32 reserved3[8]; + } LE_NARP_FRAME; typedef struct { diff -ur --new-file old/atm/led/conn.c new/atm/led/conn.c --- old/atm/led/conn.c Sat Jun 6 02:26:41 1998 +++ new/atm/led/conn.c Tue Aug 11 16:53:57 1998 @@ -45,8 +45,11 @@ /* Atm includes */ +#include #include #include + +#include "lane2.h" /* Digital includes */ #include "codes.h" diff -ur --new-file old/atm/led/kernel_itf.c new/atm/led/kernel_itf.c --- old/atm/led/kernel_itf.c Sat Jun 6 02:47:54 1998 +++ new/atm/led/kernel_itf.c Tue Aug 11 16:53:57 1998 @@ -37,6 +37,7 @@ #include /* for malloc() and free() */ /* Atm includes */ #include +#include #include /* Local includes */ @@ -99,7 +100,8 @@ int kernel_sendmsg(atmlec_msg_type type, unsigned char *mac_addr, unsigned char *atm_addr, struct atmlec_config_msg *config, - unsigned long flag, char *data, int datalen) + unsigned long flag, char *data, int datalen, + int targetless_le_arp, int no_source_le_narp) { struct atmlec_msg *mesg; @@ -113,6 +115,8 @@ if (atm_addr) memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); mesg->content.normal.flag = flag; + mesg->content.normal.targetless_le_arp = targetless_le_arp; /* LANE2 */ + mesg->content.normal.no_source_le_narp = no_source_le_narp; } else memcpy(&mesg->content.config, config, sizeof(struct atmlec_config_msg)); @@ -161,6 +165,8 @@ return "ARP_UPDATE"; case l_config: return "CONFIG"; + case l_associate_req: + return "LANE2_ASSOCIATE_REQ"; default: return "UNKNOWN MSG TYPE"; } @@ -193,9 +199,7 @@ { int retval; - fprintf(stderr, "read_from_kernel: about to read\n"); retval = read(lec_socket, buff, size); - fprintf(stderr, "read_from_kernel: read returned %d\n", retval); if (retval < 0) EVENT(EM_SERR,("Read for extra data from kernel socket failed:%s\n",strerror(errno))); return retval; diff -ur --new-file old/atm/led/kernel_itf.h new/atm/led/kernel_itf.h --- old/atm/led/kernel_itf.h Sun Feb 1 13:23:03 1998 +++ new/atm/led/kernel_itf.h Tue Aug 11 16:53:57 1998 @@ -36,7 +36,8 @@ int kernel_init(unsigned char *mac_addr, int itf_num); int kernel_sendmsg(atmlec_msg_type type, unsigned char *mac_addr, unsigned char *atm_addr, struct atmlec_config_msg *config, - unsigned long flag, char *data, int datalen); + unsigned long flag, char *data, int datalen, + int targetless_le_arp, int no_source_le_arp); int kernel_register_callback(atmlec_msg_type type, kernel_callback callback); void kernel_dispatch_handlers(void); int read_from_kernel (char *buff, int size); diff -ur --new-file old/atm/led/lane2.h new/atm/led/lane2.h --- old/atm/led/lane2.h Thu Jan 1 01:00:00 1970 +++ new/atm/led/lane2.h Tue Aug 11 16:53:57 1998 @@ -0,0 +1,8 @@ +#ifndef LANE2_H +#define LANE2_H + +extern int lane_version(void); /* returns 1 for LANE v1, 2 for LANE v2 etc */ +#define ADDR_L3 UINT32 + +#endif /* LANE2_H */ + diff -ur --new-file old/atm/led/lec.h new/atm/led/lec.h --- old/atm/led/lec.h Wed Nov 19 12:59:15 1997 +++ new/atm/led/lec.h Tue Aug 11 16:53:57 1998 @@ -130,7 +130,8 @@ MTU_1516, MTU_4544, MTU_9234, - MTU_18190 + MTU_18190, + MTU_1580 } LAN_MTU; /* INIT_METHOD diff -ur --new-file old/atm/led/lec_arp.c new/atm/led/lec_arp.c --- old/atm/led/lec_arp.c Sat Jun 6 02:46:27 1998 +++ new/atm/led/lec_arp.c Tue Aug 11 16:53:57 1998 @@ -31,7 +31,7 @@ #include #include #include -#include /* includes linux/atm.h */ +#include #include /* Include General Headers. */ @@ -75,6 +75,8 @@ ARP_XMT_CALLBACK arp_xmt_callback; FLUSH_XMT_CALLBACK flush_xmt_callback; SVC_SETUP_CALLBACK svc_setup_callback; + void (*associate_req_callback) (HANDLE lc_elan_handle, + int sizeoftlvs); /* LANE2 */ LA_ELAN_LIST elan_list; } LA_CONTEXT; @@ -90,7 +92,10 @@ LA_ELAN_CONTEXT *p_elan; ESI *to_pass; - to_pass = (ESI*)mesg->content.normal.mac_addr; + if (mesg->content.normal.targetless_le_arp) + to_pass = NULL; + else + to_pass = (ESI*)mesg->content.normal.mac_addr; utl_list_traverse(lec_arp_context.elan_list, p_elan) { lec_arp_context.arp_xmt_callback(p_elan->lc_elan_handle, @@ -108,7 +113,7 @@ lec_arp_context.flush_xmt_callback(p_elan->lc_elan_handle, to_pass,&dumb); EVENT(EM_DEBUG,("Setting flush transaction id to %lx\n",dumb)); kernel_sendmsg(l_flush_tran_id, NULL, to_pass, - NULL, dumb, NULL, 0); + NULL, dumb, NULL, 0, 0, 0); } } @@ -125,21 +130,35 @@ } } +/* LANE2: LE_ASSOCIATE.request */ +static void +kernel_associate_req_callback(struct atmlec_msg *mesg) +{ + LA_ELAN_CONTEXT *p_elan; + + utl_list_traverse(lec_arp_context.elan_list, p_elan) { + lec_arp_context.associate_req_callback(p_elan->lc_elan_handle, mesg->sizeoftlvs); + } +} + STATUS la_create (HANDLE lc_handle, ARP_XMT_CALLBACK arp_xmt_callback, FLUSH_XMT_CALLBACK flush_xmt_callback, SVC_SETUP_CALLBACK svc_setup_callback, + void (*associate_req_callback)(HANDLE lc_elan_handle, int sizeoftlvs), /* LANE2 */ HANDLE *p_la_handle) { lec_arp_context.lc_handle = lc_handle; lec_arp_context.arp_xmt_callback = arp_xmt_callback; lec_arp_context.flush_xmt_callback = flush_xmt_callback; lec_arp_context.svc_setup_callback = svc_setup_callback; + lec_arp_context.associate_req_callback = associate_req_callback; /* LANE2 */ utl_list_init(lec_arp_context.elan_list); kernel_register_callback(l_arp_xmt, kernel_arp_xmt_callback); kernel_register_callback(l_svc_setup, kernel_svc_setup_xmt_callback); + kernel_register_callback(l_associate_req, kernel_associate_req_callback); *p_la_handle = (HANDLE)&lec_arp_context; @@ -212,7 +231,8 @@ UINT16 max_unknown_frame_time, UINT32 vcc_timeout, UINT16 max_retry_count, UINT32 aging_time, UINT16 forward_delay_time, UINT16 le_arp_response_time, - UINT16 flush_timeout, UINT16 path_switching_delay) + UINT16 flush_timeout, UINT16 path_switching_delay, + unsigned int lane_version_number) { LA_ELAN_CONTEXT *p_elan; struct atmlec_config_msg conf_mesg; @@ -228,7 +248,8 @@ conf_mesg.arp_response_time = le_arp_response_time; conf_mesg.flush_timeout = flush_timeout; conf_mesg.path_switching_delay = path_switching_delay; - kernel_sendmsg(l_config, NULL, NULL, &conf_mesg, 0, NULL, 0); + conf_mesg.lane_version = lane_version_number; /* LANE2 */ + kernel_sendmsg(l_config, NULL, NULL, &conf_mesg, 0, NULL, 0, 0, 0); } STATUS @@ -237,7 +258,7 @@ BOOLEAN permanent) { kernel_sendmsg(l_addr_delete, NULL, atm_addr, NULL, - permanent==TRUE?1:0, NULL, 0); + permanent==TRUE?1:0, NULL, 0, 0, 0); return STATUS_K_SUCCESS; } @@ -246,18 +267,20 @@ * */ void -la_arp_update(HANDLE la_elan_handle, - ESI esi, - ADDR_ATM addr_atm, - BOOLEAN remote_flag, - char *tlv_list, - int sizeoftlvs) +la_arp_update(HANDLE la_elan_handle, + ESI esi, + ADDR_ATM addr_atm, + BOOLEAN remote_flag, + char *tlv_list, + int sizeoftlvs, + int targetless_le_arp, + int no_source_le_narp) { EVENT(EM_DEBUG,("ARP update for %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", esi[0],esi[1],esi[2],esi[3],esi[4],esi[5])); kernel_sendmsg(l_arp_update, (unsigned char *)esi, (unsigned char *)&addr_atm, NULL, remote_flag==TRUE?1:0, - tlv_list, sizeoftlvs); + tlv_list, sizeoftlvs, targetless_le_arp, no_source_le_narp); } void @@ -266,7 +289,7 @@ { EVENT(EM_DEBUG,("Flush complete for tran_id %lx\n", tran_id)); kernel_sendmsg(l_flush_complete, NULL, - NULL, NULL, tran_id, NULL, 0); + NULL, NULL, tran_id, NULL, 0, 0, 0); } void @@ -275,7 +298,7 @@ { kernel_sendmsg(l_topology_change, NULL, NULL, NULL, topology_change_flag==TRUE?1:0, - NULL, 0); + NULL, 0, 0, 0); } diff -ur --new-file old/atm/led/lec_arp.h new/atm/led/lec_arp.h --- old/atm/led/lec_arp.h Sun Feb 1 13:23:05 1998 +++ new/atm/led/lec_arp.h Tue Aug 11 16:53:57 1998 @@ -307,11 +307,13 @@ * Postconditions: * The p_la_handle is valid. --*/ -STATUS la_create (HANDLE lc_handle, - ARP_XMT_CALLBACK arp_xmt_callback, - FLUSH_XMT_CALLBACK flush_xmt_callback, - SVC_SETUP_CALLBACK svc_setup_callback, - HANDLE *p_la_handle); +STATUS la_create (HANDLE lc_handle, + ARP_XMT_CALLBACK arp_xmt_callback, + FLUSH_XMT_CALLBACK flush_xmt_callback, + SVC_SETUP_CALLBACK svc_setup_callback, + void (*associate_req_callback)(HANDLE lc_elan_handle, + int sizeoftlvs), /* LANE2 */ + HANDLE *p_la_handle); /*++ * ============== @@ -444,7 +446,8 @@ UINT16 forward_delay_time, UINT16 le_arp_response_time, UINT16 flush_timeout, - UINT16 path_switching_delay); + UINT16 path_switching_delay, + unsigned int lane_version_num); /* LANE2 */ /*++ * ================= @@ -538,12 +541,14 @@ * flush mechanism is invoked to facilitate the path switch. * LANE2: The TLV association is also up-to-date --*/ -void la_arp_update (HANDLE la_elan_handle, - ESI esi, - ADDR_ATM addr_atm, - BOOLEAN remote_flag, - char *tlv_list, - int sizeoftlvs); +void la_arp_update (HANDLE la_elan_handle, + ESI esi, + ADDR_ATM addr_atm, + BOOLEAN remote_flag, + char *tlv_list, + int sizeoftlvs, + int targetless_le_arp, + int no_source_le_narp); /*++ * ===================== diff -ur --new-file old/atm/led/lec_ctrl.c new/atm/led/lec_ctrl.c --- old/atm/led/lec_ctrl.c Fri Jul 3 21:16:31 1998 +++ new/atm/led/lec_ctrl.c Tue Aug 11 16:53:58 1998 @@ -65,6 +65,8 @@ #include #include #include +#include /* for select() */ +#include /* for select() */ #include @@ -79,6 +81,7 @@ #include "atmsap.h" /* ATM SAP definition */ #include "system.h" /* ATM Subsystem Specific Stuff */ #include "g_event.h" +#include "lane2.h" /* New stuff in LANE v2 */ /* Include Headers for Mapping Module Interfaces. */ @@ -111,11 +114,17 @@ * structure are prefixed with their C# designation used in the * specification. Refer to the specification for detailed descriptions of * these values. + * + * LANE2: C2c, C3c, C5c, C29c, C32c and C34c from LANE spec V2.0 + * (section 5.1.1) are not needed since lc_register() copies the values + * and the originals are hence never changed. + * */ typedef struct { - ADDR_ATM c1_my_atm_addr; + ADDR_ATM c1n_my_atm_addr; /* LANE2: LEC's non-muxed ATM address */ LAN_TYPE c2_lan_type; LAN_MTU c3_lan_mtu; + LAN_MTU c3c_lan_mtu; /* LANE2: configured (static) lan mtu */ BOOLEAN c4_proxy_flag; UINT8 elan_name_size; /* For config request */ char c5_elan_name[32]; /* For config request */ @@ -135,6 +144,21 @@ UINT16 c20_le_arp_response_time; UINT16 c21_flush_timeout; UINT16 c22_path_switching_delay; + BOOLEAN c29_v2_capable; /* LANE2 stuff below */ + UINT32 c31_elan_id; /* for llc-muxed frames */ + BOOLEAN c32_selective_mcast; /* not supported currently */ + UINT16 c33_fwd_disc_timeout; + BOOLEAN c34_llc_mux_capable; /* not supported */ + ADDR_ATM c35_preferred_les; + ADDR_L3 c36_l3_address; /* only IP is supported */ + UINT16 c36_l3_address_size; /* size of the above in bytes */ + UINT32 c37_min_reconfig_delay; /* in milliseconds */ + UINT32 c38_max_reconfig_delay; /* in milliseconds */ + /* add c34 and c39 later if needed */ + int sizeoftlvs; /* total size of TLVs associated with this LEC */ + char *tlvs; /* the TLVs */ + const char *foreId; + UINT8 extra_tlvs[7]; } LEC_STATE; typedef struct @@ -362,7 +386,7 @@ /* Protos */ static const char *state_name (UINT16 s); static const char *event_name (UINT16 s); -static void tlv_parse (LC_ELAN_CONTEXT *p_elan, +static int tlv_parse (LC_ELAN_CONTEXT *p_elan, UINT8 buffer[], UINT32 length, UINT8 *p_tlv_index); @@ -412,14 +436,18 @@ p_conn_info->addr.sas_family = AF_ATMSVC; p_conn_info->conqos.aal = ATM_AAL5; - + /* Set the forward and backward Max CPCS-SDU Size */ switch(blli_codepoint) { case BLLI_CONTROL: case BLLI_DIRECT_802_3: - case BLLI_BUS_802_3: + case BLLI_BUS_802_3: /* LANE2: MTU can be 1580 too (IEEE 802.1p/Q) */ + p_conn_info->conqos.rxtp.max_sdu = p_elan->lec_state.c3_lan_mtu; + p_conn_info->conqos.txtp.max_sdu = p_elan->lec_state.c3_lan_mtu; +#if 0 /* the old version */ p_conn_info->conqos.rxtp.max_sdu = 1516; p_conn_info->conqos.txtp.max_sdu = 1516; +#endif break; case BLLI_DIRECT_802_5: case BLLI_BUS_802_5: @@ -654,7 +682,7 @@ frame.src_lan_dst.tag = hton16 (TAG_MAC_ADDR); ESI_COPY (p_dest->mac_addr, frame.src_lan_dst.mac_addr); - ATM_COPY (p_elan->lec_state.c1_my_atm_addr, frame.src_atm_addr); + ATM_COPY (p_elan->lec_state.c1n_my_atm_addr, frame.src_atm_addr); if (reg) { @@ -762,6 +790,7 @@ static void act_atm_addr_cancel (HANDLE lc_elan_handle); static void act_ilmi_ld_1st_get (HANDLE lc_elan_handle); static void act_ilmi_next_get (HANDLE lc_elan_handle); +static void act_wait_random (HANDLE lc_elan_handle); /* LANE2: 5.2.1.4 */ static void act_lecs_svc_setup (HANDLE lc_elan_handle); static void act_lecs_wsvc_setup (HANDLE lc_elan_handle); static void act_config_req_xmt (HANDLE lc_elan_handle); @@ -890,14 +919,14 @@ TRAN (S_ILMI_WAIT, E_TIMEOUT_NORETRY, S_ILMI_WAIT, act_ilmi_ld_1st_get, NULL, NULL); TRAN (S_LECS_SVC_WAIT, E_LECS_SVC_READY, S_CONFIG_WAIT, act_timer_cancel, act_config_req_xmt, NULL); TRAN (S_LECS_SVC_WAIT, E_LECS_SVC_RELEASE, S_ILMI_WAIT, act_timer_cancel, act_ilmi_next_get, NULL); - TRAN (S_LECS_SVC_WAIT, E_TIMEOUT_NORETRY, S_ILMI_WAIT, act_ilmi_next_get, NULL, NULL); + TRAN (S_LECS_SVC_WAIT, E_TIMEOUT_NORETRY, S_ILMI_WAIT, act_wait_random, act_ilmi_next_get, NULL); TRAN (S_LECS_WSVC_WAIT, E_LECS_SVC_READY, S_CONFIG_WAIT, act_timer_cancel, act_config_req_xmt, NULL); TRAN (S_LECS_WSVC_WAIT, E_LECS_SVC_RELEASE, S_ILMI_WAIT, act_timer_cancel, act_ilmi_ld_1st_get, NULL); - TRAN (S_LECS_WSVC_WAIT, E_TIMEOUT_NORETRY, S_ILMI_WAIT, act_ilmi_ld_1st_get, NULL, NULL); + TRAN (S_LECS_WSVC_WAIT, E_TIMEOUT_NORETRY, S_ILMI_WAIT, act_wait_random, act_ilmi_ld_1st_get, NULL); TRAN (S_CONFIG_WAIT, E_RCV_CONFIG_RSP, S_LES_SVC_WAIT, act_timer_cancel, act_lecs_vc_teardown, act_les_svc_setup); TRAN (S_CONFIG_WAIT, E_TIMEOUT_RETRY, S_CONFIG_WAIT, act_config_req_xmt, NULL, NULL); - TRAN (S_CONFIG_WAIT, E_TIMEOUT_NORETRY, S_ILMI_WAIT, act_lecs_vc_teardown, act_ilmi_next_get, NULL); - TRAN (S_CONFIG_WAIT, E_LECS_SVC_RELEASE, S_ILMI_WAIT, act_timer_cancel, act_ilmi_next_get, NULL); + TRAN (S_CONFIG_WAIT, E_TIMEOUT_NORETRY, S_ILMI_WAIT, act_lecs_vc_teardown, act_wait_random, act_ilmi_next_get); + TRAN (S_CONFIG_WAIT, E_LECS_SVC_RELEASE, S_ILMI_WAIT, act_timer_cancel, act_wait_random, act_ilmi_next_get); TRAN (S_LES_SVC_WAIT, E_LES_SVC_READY, S_JOIN_WAIT, act_timer_cancel, act_join_req_xmt, NULL); TRAN (S_LES_SVC_WAIT, E_LES_SVC_RELEASE, S_ILMI_WAIT, act_timer_cancel, act_ilmi_next_get, NULL); TRAN (S_LES_SVC_WAIT, E_TIMEOUT_NORETRY, S_ILMI_WAIT, act_ilmi_next_get, NULL, NULL); @@ -1209,7 +1238,7 @@ LC_ELAN_CONTEXT *p_elan = (LC_ELAN_CONTEXT*) lc_elan_handle; (void) addr_reg_atm_addr_dealloc (p_elan->addr_reg_client_handle, - &p_elan->lec_state.c1_my_atm_addr); + &p_elan->lec_state.c1n_my_atm_addr); } /*++ @@ -1268,6 +1297,30 @@ } /*++ +* =================== +* = act_wait_random = +* =================== +* +* LANE2: 5.2.1.4 sleep random time before trying to reconnect +--*/ +static void act_wait_random (HANDLE lc_elan_handle) + { + + struct timeval tv; + int millis, interval; + LC_ELAN_CONTEXT *p_elan = (LC_ELAN_CONTEXT *) lc_elan_handle; + + srand(time(NULL)); + interval = p_elan->lec_state.c38_max_reconfig_delay - p_elan->lec_state.c37_min_reconfig_delay; + millis = (rand() % interval) + p_elan->lec_state.c37_min_reconfig_delay; + tv.tv_sec = (millis - (millis % 1000)) / 1000; + tv.tv_usec = (millis % 1000) * 1000; + + (void)select(0, NULL, NULL, NULL, &tv); + + return; + } +/*++ * ====================== * = act_lecs_svc_setup = * ====================== @@ -1358,50 +1411,97 @@ static void act_config_req_xmt (HANDLE lc_elan_handle) { LC_ELAN_CONTEXT *p_elan; - LE_CONFIG_FRAME frame; + LE_CONFIG_FRAME *frame; STATUS status; + int frame_size; + char *tlvdata; /* for filling in the TLVs */ p_elan = (LC_ELAN_CONTEXT *) lc_elan_handle; - memset(&frame, 0, sizeof (LE_JOIN_FRAME)); - - lc_ctrl_hdr_make (lc_elan_handle, &frame.hdr, LE_CONFIG_REQ); - frame.hdr.req_lec_id = hton16 (0); + /* allocate size for the frame and both TLVs that can be + present, X5 adjustement TLV and l3 address TLV */ + frame_size = ( sizeof(LE_CONFIG_FRAME) + + 5 + 0 + + 5 + p_elan->lec_state.c36_l3_address_size ); + frame = os_mem_alloc(frame_size); + tlvdata = (char *)(frame +1); + + lc_ctrl_hdr_make (lc_elan_handle, &frame->hdr, LE_CONFIG_REQ); + frame->hdr.req_lec_id = hton16 (0); + if (p_elan->lec_state.c29_v2_capable) /* LANE2 */ + frame->hdr.flags = hton16(LE_FLAG_V2_CAPABLE); - ATM_COPY (p_elan->lec_state.c1_my_atm_addr, frame.src_atm_addr); + ATM_COPY (p_elan->lec_state.c1n_my_atm_addr, frame->src_atm_addr); switch (p_elan->lec_state.c2_lan_type) { case LAN_802_3 : - frame.lan_type = 1; + frame->lan_type = 1; break; case LAN_802_5 : - frame.lan_type = 2; + frame->lan_type = 2; break; default: - frame.lan_type =1; + frame->lan_type =1; } switch (p_elan->lec_state.c3_lan_mtu) { - case MTU_UNSPEC : frame.max_frame_size = 0; break; - case MTU_1516 : frame.max_frame_size = 1; break; - case MTU_4544 : frame.max_frame_size = 2; break; - case MTU_9234 : frame.max_frame_size = 3; break; - case MTU_18190 : frame.max_frame_size = 4; break; - } + case MTU_UNSPEC : frame->max_frame_size = 0; break; + case MTU_1516 : frame->max_frame_size = 1; break; + case MTU_1580 : frame->max_frame_size = 1; break; /* LANE2 5.3.1.2 */ + case MTU_4544 : frame->max_frame_size = 2; break; + case MTU_9234 : frame->max_frame_size = 3; break; + case MTU_18190 : frame->max_frame_size = 4; break; + } + + frame->elan_name_size = p_elan->lec_state.elan_name_size; + memcpy(frame->elan_name, p_elan->lec_state.c5_elan_name, + MIN (frame->elan_name_size, 32)); - frame.tlv_count = 0; - - frame.elan_name_size = p_elan->lec_state.elan_name_size; - memcpy(frame.elan_name, p_elan->lec_state.c5_elan_name, - MIN (frame.elan_name_size, 32)); + frame->tlv_count = 0; + frame_size = sizeof (LE_CONFIG_FRAME); + /* LANE2: add X5 adjustement TLV */ + if (p_elan->lec_state.c3_lan_mtu == MTU_1580) { +#if 0 + *tlvdata++ = 0x00; *tlvdata++ = 0xa0; + *tlvdata++ = 0x3e; *tlvdata++ = 0x2c; +#endif + *(UINT32 *)tlvdata = TLV_X5_ADJUSTEMENT; + tlvdata += sizeof(TLV_X5_ADJUSTEMENT); /* should be 4 */ + *tlvdata++ = 0x00; /* length 0 */ + frame_size += 5; + frame->tlv_count += 1; + } + + /* LANE2: 5.3.1.1, add L3 Address TLV if l3_address not empty */ + if (p_elan->lec_state.c36_l3_address_size != 0) { + int l3_address_size = p_elan->lec_state.c36_l3_address_size; + ADDR_L3 l3_addr = hton32(p_elan->lec_state.c36_l3_address); + +#if 0 + *tlvdata++ = 0x00; *tlvdata++ = 0xa0; + *tlvdata++ = 0x3e; *tlvdata++ = 0x11; +#endif + *(UINT32 *)tlvdata = TLV_L3_ADDRESS; + tlvdata += sizeof(TLV_L3_ADDRESS); + *tlvdata++ = l3_address_size; + memcpy(tlvdata, &l3_addr, l3_address_size); + tlvdata += l3_address_size; + frame_size += l3_address_size; + frame->tlv_count += 1; + } + + +#if 0 /* sleep() disabled, hessu@cs.tut.fi 13.2.1998 */ sleep(1); +#endif status = cm_sap_xmt_vc (p_elan->lecs_conn_handle, - &frame, - sizeof (frame), + frame, + frame_size, USER_DATA_INTERNAL, NULL); + os_mem_dealloc(frame); if (status != STATUS_K_SUCCESS) p_elan->ctrl_xmt_failure_count += 1; else @@ -1446,8 +1546,10 @@ act_join_req_xmt(HANDLE lc_elan_handle) { LC_ELAN_CONTEXT *p_elan; - LE_JOIN_FRAME frame; + LE_JOIN_FRAME *frame; STATUS status; + int frame_size; + char *tlvdata; p_elan = (LC_ELAN_CONTEXT *) lc_elan_handle; @@ -1456,57 +1558,112 @@ */ p_elan->lec_state.c6_my_mac_addr.registered = FALSE; - memset(&frame, 0, sizeof (LE_JOIN_FRAME)); - + frame_size = ( sizeof(LE_JOIN_FRAME) + + 5 + p_elan->lec_state.c36_l3_address_size + + 5 + 0 + /* X5 adjustement */ + 5 + 20); /* preferred LES */ + + if (strlen(p_elan->lec_state.foreId) > 0) + frame_size += 5 + strlen(p_elan->lec_state.foreId); + + frame = os_mem_alloc(frame_size); + memset(frame, 0, frame_size); + tlvdata = (char *)(frame + 1); + p_elan->lec_state.c14_lec_id = 0; - lc_ctrl_hdr_make (lc_elan_handle, &frame.hdr, LE_JOIN_REQ); + lc_ctrl_hdr_make (lc_elan_handle, &frame->hdr, LE_JOIN_REQ); - frame.hdr.flags = p_elan->lec_state.c4_proxy_flag ? + frame->hdr.flags = p_elan->lec_state.c4_proxy_flag ? hton16 (LE_FLAG_PROXY) : 0; - + frame->hdr.flags |= (p_elan->lec_state.c29_v2_capable) ? + hton16 (LE_FLAG_V2_CAPABLE) : 0; /* LANE2 */ + p_elan->lec_state.c6_my_mac_addr.registered = TRUE; - frame.src_lan_dst.tag = hton16 (TAG_MAC_ADDR); + frame->src_lan_dst.tag = hton16 (TAG_MAC_ADDR); ESI_COPY (p_elan->lec_state.c6_my_mac_addr.mac_addr, - frame.src_lan_dst.mac_addr); + frame->src_lan_dst.mac_addr); - ATM_COPY (p_elan->lec_state.c1_my_atm_addr, frame.src_atm_addr); + ATM_COPY (p_elan->lec_state.c1n_my_atm_addr, frame->src_atm_addr); switch (p_elan->lec_state.c2_lan_type) { case LAN_802_3 : - frame.lan_type = 1; + frame->lan_type = 1; break; case LAN_802_5 : - frame.lan_type = 2; + frame->lan_type = 2; break; default: - frame.lan_type = 1; + frame->lan_type = 1; } switch (p_elan->lec_state.c3_lan_mtu) { case MTU_UNSPEC: - frame.max_frame_size = 0; + frame->max_frame_size = 0; break; - case MTU_1516 : frame.max_frame_size = 1; break; - case MTU_4544 : frame.max_frame_size = 2; break; - case MTU_9234 : frame.max_frame_size = 3; break; - case MTU_18190 : frame.max_frame_size = 4; break; + case MTU_1516 : frame->max_frame_size = 1; break; + case MTU_1580 : frame->max_frame_size = 1; break; /* LANE2 5.4.3 */ + case MTU_4544 : frame->max_frame_size = 2; break; + case MTU_9234 : frame->max_frame_size = 3; break; + case MTU_18190 : frame->max_frame_size = 4; break; } - frame.tlv_count = 0; + frame->tlv_count = 0; - frame.elan_name_size = p_elan->lec_state.elan_name_size_join; - memcpy(frame.elan_name, p_elan->lec_state.c5_elan_name_join, - MIN (frame.elan_name_size, 32)); + frame->elan_name_size = p_elan->lec_state.elan_name_size_join; + memcpy(frame->elan_name, p_elan->lec_state.c5_elan_name_join, + MIN (frame->elan_name_size, 32)); EVENT(EM_DEBUG,("ELAN NAME:%s len:%d\n",p_elan->lec_state.c5_elan_name_join, - MIN(frame.elan_name_size, 32))); + MIN(frame->elan_name_size, 32))); + + /* LANE2: add X5 adjustement TLV */ + if (p_elan->lec_state.c3_lan_mtu == MTU_1580) { +#if 0 + *tlvdata++ = 0x00; *tlvdata++ = 0xa0; + *tlvdata++ = 0x3e; *tlvdata++ = 0x2c; +#endif + *(UINT32 *)tlvdata = TLV_X5_ADJUSTEMENT; + tlvdata += sizeof(TLV_X5_ADJUSTEMENT); /* should be 4 */ + *tlvdata++ = 0x00; /* length 0 */ + frame_size += 5; + frame->tlv_count += 1; + } + + /* LANE2: 5.3.1.1, add L3 Address TLV if l3_address not empty */ + if (p_elan->lec_state.c36_l3_address_size != 0) { + int l3_address_size = p_elan->lec_state.c36_l3_address_size; + ADDR_L3 l3_addr = hton32(p_elan->lec_state.c36_l3_address); + +#if 0 + *tlvdata++ = 0x00; *tlvdata++ = 0xa0; + *tlvdata++ = 0x3e; *tlvdata++ = 0x11; +#endif + *(UINT32 *)tlvdata = TLV_L3_ADDRESS; + tlvdata += sizeof(TLV_L3_ADDRESS); + *tlvdata++ = l3_address_size; + memcpy(tlvdata, &l3_addr, l3_address_size); + tlvdata += l3_address_size; + frame_size += l3_address_size; + frame->tlv_count += 1; + } + + /* strictly Fore specific hack */ + if ( strlen(p_elan->lec_state.foreId) > 0) { + *tlvdata++ = 0x00; *tlvdata++ = 0x20; + *tlvdata++ = 0x48; *tlvdata++ = 0x08; + *tlvdata++ = strlen(p_elan->lec_state.foreId); + strncpy(tlvdata, p_elan->lec_state.foreId, strlen(p_elan->lec_state.foreId)); + tlvdata += strlen(p_elan->lec_state.foreId); + frame->tlv_count += 1; + } sleep(1); status = cm_sap_xmt_vc (p_elan->ctrl_direct_conn_handle, - &frame, - sizeof (frame), + frame, + frame_size, USER_DATA_INTERNAL, NULL); + os_mem_dealloc(frame); if (status != STATUS_K_SUCCESS) p_elan->ctrl_xmt_failure_count += 1; else @@ -1541,7 +1698,7 @@ frame.target_lan_dst.mac_addr[4] = 0xff; frame.target_lan_dst.mac_addr[5] = 0xff; - ATM_COPY (p_elan->lec_state.c1_my_atm_addr, frame.src_atm_addr); + ATM_COPY (p_elan->lec_state.c1n_my_atm_addr, frame.src_atm_addr); p_elan->arps_sent += 1; @@ -1636,6 +1793,7 @@ p_elan->ctrl_dist_conn_handle = NULL; cm_sap_svc_teardown (teardown); } + act_wait_random(p_elan); /* LANE2 */ } /*++ @@ -1662,6 +1820,7 @@ cm_sap_svc_teardown (p_elan->mcast_rcv_conn_handle); p_elan->mcast_rcv_conn_handle = NULL; } + act_wait_random(p_elan); /* LANE2 */ } @@ -1701,7 +1860,7 @@ { case ADDR_REG_EVENT_ATM_ADDR_ALLOCATED : - ATM_COPY (*p_atm_addr, p_elan->lec_state.c1_my_atm_addr); + ATM_COPY (*p_atm_addr, p_elan->lec_state.c1n_my_atm_addr); sm_exec (context, E_AREG_DONE); break; @@ -1723,6 +1882,9 @@ * * LANE2: LE_ARP_FRAME can now contain TLVs and therefore has * variable size. Total length of TLVs is in sizeoftlvs +* Note: this does _not_ update the TLV info in p_elan->tlvs +* If sizeofltvs == 0 then the default TLVs associated with this lec +* will be used. Also, if esi == NULL sends targetless LE_ARP * --*/ static void lc_arp_xmt (HANDLE lc_elan_handle, @@ -1735,19 +1897,29 @@ int retval; char *buff; - framelength = sizeof(LE_ARP_FRAME) + sizeoftlvs; - p_elan = (LC_ELAN_CONTEXT *) lc_elan_handle; + if (sizeoftlvs == 0) + framelength = sizeof(LE_ARP_FRAME) + p_elan->lec_state.sizeoftlvs; + else + framelength = sizeof(LE_ARP_FRAME) + sizeoftlvs; + frame = (LE_ARP_FRAME*)os_mem_alloc(framelength); memset(frame, 0, framelength); lc_ctrl_hdr_make (lc_elan_handle, &frame->hdr, LE_ARP_REQ); - frame->src_lan_dst.tag = hton16 (TAG_NOT_PRESENT); - frame->target_lan_dst.tag = hton16 (TAG_MAC_ADDR); - ESI_COPY (esi, frame->target_lan_dst.mac_addr); - ATM_COPY (p_elan->lec_state.c1_my_atm_addr, frame->src_atm_addr); + frame->src_lan_dst.tag = hton16 (TAG_MAC_ADDR); + ESI_COPY (p_elan->lec_state.c6_my_mac_addr.mac_addr, + frame->src_lan_dst.mac_addr); + if (esi != NULL) { /* esi == NULL means targetless LE_ARP */ + frame->target_lan_dst.tag = hton16 (TAG_MAC_ADDR); + ESI_COPY (esi, frame->target_lan_dst.mac_addr); + } + else + frame->target_lan_dst.tag = hton16 (TAG_NOT_PRESENT); + + ATM_COPY (p_elan->lec_state.c1n_my_atm_addr, frame->src_atm_addr); if (sizeoftlvs != 0) { buff = os_mem_alloc(sizeoftlvs); @@ -1762,9 +1934,19 @@ fprintf(stderr, "lc_arp_xmt(): after memcpy\n"); os_mem_dealloc(buff); } - - EVENT (EM_XDATA, ("Sending LE-ARP for address: %02x-%02x-%02x-%02x-%02x-%02x\n", - esi[0], esi[1], esi[2], esi[3], esi[4], esi[5])); + else { + memcpy(frame + 1, p_elan->lec_state.tlvs, p_elan->lec_state.sizeoftlvs); + EVENT(EM_DEBUG,("lc_arp_xmt(): length of tlvs %d\n", p_elan->lec_state.sizeoftlvs)); + } + if (sizeoftlvs != 0 || p_elan->lec_state.sizeoftlvs != 0) + frame->tlv_count++; + + if (esi != NULL) { + EVENT (EM_XDATA, ("Sending LE-ARP for address: %02x-%02x-%02x-%02x-%02x-%02x\n", + esi[0], esi[1], esi[2], esi[3], esi[4], esi[5])); + } + else + EVENT (EM_XDATA, ("Sending targetless LE-ARP\n")); p_elan->arps_sent += 1; @@ -1806,7 +1988,7 @@ &frame.hdr, LE_FLUSH_REQ); - ATM_COPY (p_elan->lec_state.c1_my_atm_addr, frame.src_atm_addr); + ATM_COPY (p_elan->lec_state.c1n_my_atm_addr, frame.src_atm_addr); for(i=0;ilec_state.tlvs != NULL) + os_mem_dealloc(p_elan->lec_state.tlvs); /* free old TLVs (if any) */ + p_elan->lec_state.sizeoftlvs = sizeoftlvs; + p_elan->lec_state.tlvs = buff; +} + + /*++ * ==================== @@ -1935,6 +2147,7 @@ lc_arp_xmt, lc_flush_xmt, lc_svc_setup, + associate_req, /* LANE2 */ &p_context->la_handle); if (status != STATUS_K_SUCCESS) { @@ -2008,7 +2221,11 @@ BOOLEAN proxy_flag, HANDLE lport_handle, char *p_text, - HANDLE *p_lc_elan_handle) + HANDLE *p_lc_elan_handle, + BOOLEAN v2_capable, + ADDR_ATM preferred_les, + ADDR_L3 l3_address, + const char *foreId) { LC_CONTEXT *p_context; LC_ELAN_CONTEXT *p_elan; @@ -2029,6 +2246,14 @@ EVENT(EM_DEBUG,("Lc_register, lc_handle:%p p_elan:%p\n",lc_handle, p_elan)); + p_elan->lec_state.extra_tlvs[0] = 0x00; + p_elan->lec_state.extra_tlvs[1] = 0xa0; + p_elan->lec_state.extra_tlvs[2] = 0x3e; + p_elan->lec_state.extra_tlvs[3] = 0x13; + p_elan->lec_state.extra_tlvs[4] = 0x02; + p_elan->lec_state.extra_tlvs[5] = 0x00; + p_elan->lec_state.extra_tlvs[6] = 0x0f; + /* Initialize the fields of the elan block. */ p_elan->lc_handle = lc_handle; @@ -2059,8 +2284,8 @@ /* Initialize the fields of the lec state. */ - p_elan->lec_state.c2_lan_type = lan_type; - p_elan->lec_state.c3_lan_mtu = max_frame_size; + p_elan->lec_state.c2_lan_type = lan_type; + p_elan->lec_state.c3_lan_mtu = max_frame_size; p_elan->lec_state.c4_proxy_flag = proxy_flag; p_elan->lec_state.elan_name_size = strlen (p_elan_name); strncpy(p_elan->lec_state.c5_elan_name, p_elan_name, @@ -2071,7 +2296,11 @@ MIN(32, p_elan->lec_state.elan_name_size_join)); } p_elan->lec_state.c7_control_timeout = 10; + if (p_elan->lec_state.c29_v2_capable) + p_elan->lec_state.c7_control_timeout = 30; /* LANE2 */ p_elan->lec_state.c10_max_unknown_frame_count = 1; + if (p_elan->lec_state.c29_v2_capable) + p_elan->lec_state.c10_max_unknown_frame_count = 10; /* LANE2 */ p_elan->lec_state.c11_max_unknown_frame_time = 1; p_elan->lec_state.c12_vcc_timeout = 1200; p_elan->lec_state.c13_max_retry_count = 2; @@ -2082,6 +2311,26 @@ p_elan->lec_state.c21_flush_timeout = 4; p_elan->lec_state.c22_path_switching_delay = 6; + /* LANE2 configuration variables follow */ + p_elan->lec_state.c29_v2_capable = v2_capable; + p_elan->lec_state.c31_elan_id = 0; + p_elan->lec_state.c32_selective_mcast = FALSE; + p_elan->lec_state.c33_fwd_disc_timeout = 60; + p_elan->lec_state.c34_llc_mux_capable = FALSE; + p_elan->lec_state.c35_preferred_les = preferred_les; + p_elan->lec_state.c36_l3_address = l3_address; + p_elan->lec_state.c37_min_reconfig_delay = 1; /* milliseconds */ + p_elan->lec_state.c38_max_reconfig_delay = 5000; /* milliseconds */ + + /* Fore switches can display some extra data about client + * if asked with a correct TLV + */ + if (strlen(foreId) > 0) + p_elan->lec_state.foreId = foreId; + else + p_elan->lec_state.foreId = "\0"; + + /* LANE counters */ p_elan->illegal_frame_rcv_count = 0; p_elan->ctrl_xmt_failure_count = 0; p_elan->illegal_transition_count = 0; @@ -2149,7 +2398,8 @@ p_elan->lec_state.c18_forward_delay_time, p_elan->lec_state.c20_le_arp_response_time, p_elan->lec_state.c21_flush_timeout, - p_elan->lec_state.c22_path_switching_delay); + p_elan->lec_state.c22_path_switching_delay, + (v2_capable)? 2:1); /* Register as a client to the Address Registration module. */ @@ -2202,13 +2452,16 @@ #endif status = addr_reg_atm_addr_dealloc (p_elan->addr_reg_client_handle, - &p_elan->lec_state.c1_my_atm_addr); + &p_elan->lec_state.c1n_my_atm_addr); addr_reg_client_deregister(p_elan->addr_reg_client_handle); la_deregister (p_elan->la_elan_handle); utl_list_delete (p_context->elan_list, p_elan); + + if (p_elan->lec_state.tlvs != NULL) /* LANE2 */ + os_mem_dealloc(p_elan->lec_state.tlvs); /* free old TLVs (if any) */ os_mem_dealloc (p_elan); } @@ -2268,7 +2521,7 @@ la_elan_reset (p_elan->la_elan_handle); */ (void) addr_reg_atm_addr_dealloc (p_elan->addr_reg_client_handle, - &p_elan->lec_state.c1_my_atm_addr); + &p_elan->lec_state.c1n_my_atm_addr); sig_reset(42); /* @@ -2601,13 +2854,20 @@ * Issues: * None * +* Returns: +* 0 for successful parsing +* 1 type value all 0s type +* 2 for unknown type +* 3 for short TLV +* 4 for incorrect length for Value --*/ -void +int tlv_parse (LC_ELAN_CONTEXT *p_elan, - UINT8 buffer[], - UINT32 length, - UINT8 *p_tlv_index) + UINT8 buffer[], /* pointer to the frame */ + UINT32 length, /* length of packet inc. TLVs */ + UINT8 *p_tlv_index) /* pointer to the current TLV */ { + LE_CONFIG_FRAME *p_frame = (LE_CONFIG_FRAME *)buffer; UINT32 tlv_type; UINT8 tlv_length; UINT8 tlv_value1; @@ -2617,7 +2877,7 @@ if (length - *p_tlv_index < 5) { EVENT (EM_EVENT, ("TLV too short.\n")); - return; + return (3); } /* Extract the tlv_type, length, and value from the buffer. */ @@ -2630,10 +2890,16 @@ (buffer [i + 3]); tlv_length = buffer[i + 4]; i += 5; + *p_tlv_index = i; + + if (tlv_type == (UINT32)0) { + EVENT (EM_EVENT, ("TLV type missing.\n")); /* LANE2: 4.3.12 */ + return (1); + } if ((UINT32) (i + tlv_length) > length) { EVENT (EM_EVENT, ("TLV value missing, type = %08lx.\n", tlv_type)); - return; + return (3); } tlv_value1 = 0; @@ -2641,6 +2907,8 @@ tlv_value4 = 0; switch (tlv_length) { + case 0 : /* LANE2 has 0-length TLVs */ + break; case 1 : tlv_value1 = buffer [i]; *p_tlv_index = i + 1; @@ -2658,11 +2926,29 @@ (buffer [i + 3]); *p_tlv_index = i + 4; break; + + case 20 : /* LANE2: e.g. preferred LES */ + *p_tlv_index = i + 20; + break; + + default: /* LANE2: Config-Frag-Info and L3-Address have variable lengths */ + *p_tlv_index = i + tlv_length; + break; + } + /* Verify correct TVL lengths */ switch (tlv_type) { + case TLV_X5_ADJUSTEMENT: /* LANE2 */ + if (tlv_length != 0) { + EVENT (EM_EVENT, ("Incorrect TLV length=%d for type %08lx.\n", + tlv_length, tlv_type)); + return (4); + } + break; + case TLV_CTRL_TIMEOUT : case TLV_MAX_UNKNOWN_COUNT : case TLV_MAX_UNKNOWN_TIME : @@ -2674,10 +2960,11 @@ case TLV_LOCAL_SEG_ID : case TLV_MCAST_VCC_TYPE : case TLV_CONNECT_COMPLETION_TIMER : + case TLV_SERVICE_CATEGORY : /* LANE2 */ if (tlv_length != 2) { EVENT (EM_EVENT, ("Incorrect TLV length=%d for type=%08lx.\n", tlv_length, tlv_type)); - return; + return (4); } break; @@ -2685,10 +2972,20 @@ case TLV_AGING_TIME : case TLV_MCAST_VCC_AVG_RATE : case TLV_MCAST_VCC_PEAK_RATE : + case TLV_ELAN_ID : /* LANE2 */ if (tlv_length != 4) { EVENT (EM_EVENT, ("Incorrect TLV length=%d for type=%08lx.\n", tlv_length, tlv_type)); - return; + return (4); + } + break; + + case TLV_PREFERRED_LES : /* Both here LANE2 */ + case TLV_LLC_MUXED_ATM_ADDRESS : + if (tlv_length != 20) { + EVENT (EM_EVENT, ("Incorrect TLV length=%d for type=%08lx.\n", + tlv_length, tlv_type)); + return(4); } break; } @@ -2734,17 +3031,61 @@ p_elan->lec_state.c22_path_switching_delay = tlv_value2; break; + case TLV_X5_ADJUSTEMENT : + if (lane_version() != 2) { + EVENT (EM_EVENT, ("Acting as non LANEv2 client, ignoring X5 Adj. TLV\n")); + return(0); + } + if (ntoh16(p_frame->hdr.op_code) == LE_JOIN_RSP) { + EVENT (EM_EVENT, ("X5 Adjustement TLV received with LE_JOIN_RSP frame. See LANE2: 5.3.1.2\n")); + return(0); + } + switch (p_frame->max_frame_size) { + case 1: + case 2: + if (ntoh16(p_frame->hdr.flags) & LE_FLAG_V2_CAPABLE) + p_elan->lec_state.c3_lan_mtu = MTU_1580; + break; + case 5: + if (ntoh16(p_frame->hdr.flags) & LE_FLAG_V2_CAPABLE) + p_elan->lec_state.c3_lan_mtu = MTU_1580; + else + EVENT (EM_EVENT, ("Received X5 max. frame size but V2 Capable flag was not set\n")); + break; + default: + break; + } + break; + + case TLV_PREFERRED_LES : /* toimiiko ??? */ + memcpy (&p_elan->lec_state.c35_preferred_les, buffer + i, 20); +#if 0 + ATM_COPY (buffer + i, p_elan->lec_state.c35_preferred_les); +#endif + break; + + case TLV_CONFIG_FRAG_INFO : + EVENT (EM_SERR, ("Config-Frag-Info received but not supported. Tough luck.\n")); + break; + + case TLV_ELAN_ID : /* LANE2: LLC-muxed stuff */ + p_elan->lec_state.c31_elan_id = tlv_value4; + case TLV_LLC_MUXED_ATM_ADDRESS : /* LANE2 */ + case TLV_SERVICE_CATEGORY : /* LANE2 */ + case TLV_L3_ADDRESS : /* LANE2 */ case TLV_LOCAL_SEG_ID : case TLV_MCAST_VCC_TYPE : case TLV_MCAST_VCC_AVG_RATE : case TLV_MCAST_VCC_PEAK_RATE : case TLV_CONNECT_COMPLETION_TIMER : + default : EVENT (EM_EVENT, ("Unsupported TLV received, type=%08lx.\n", tlv_type)); break; } -} + return (0); +} /*++ * ================== @@ -2758,7 +3099,7 @@ { LE_CONFIG_FRAME *p_frame; UINT8 tlv_index; - + p_frame = (LE_CONFIG_FRAME *)p_packet; if (length < sizeof (LE_CONFIG_FRAME)) { @@ -2772,12 +3113,29 @@ ntoh16 (p_frame->hdr.status))); return; } - + + if (length > sizeof (LE_CONFIG_FRAME)) { + EVENT (EM_EVENT, ("Received Config Response with TLVs\n")); + } + + /* LANE2: If X5 Adj. TLV is present these values may change + * during tlv_parse(). In other words, do not move this + * switch block below tvl_parse(). These values will stay + * if X5 Adj. TLV is not received with LE_CONFIG_RSP frame. + * The correct handling of different flag, client version and TLV + * value combinations needs to be checked later. + */ switch (p_frame->max_frame_size) { case 1 : p_elan->lec_state.c3_lan_mtu = MTU_1516; break; case 2 : p_elan->lec_state.c3_lan_mtu = MTU_4544; break; case 3 : p_elan->lec_state.c3_lan_mtu = MTU_9234; break; case 4 : p_elan->lec_state.c3_lan_mtu = MTU_18190; break; + case 5 : /* LANE2 */ + if (lane_version() == 2) + p_elan->lec_state.c3_lan_mtu = MTU_1580; + else + EVENT (EM_EVENT, ("Acting as non LANEv2 client, ignoring X5 max. frame size\n")); + break; default : break; } @@ -2806,7 +3164,9 @@ if (tlv_index < length) { while (tlv_index < length) { - tlv_parse(p_elan, p_packet, length, &tlv_index); + if ( 1 == tlv_parse(p_elan, p_packet, length, &tlv_index) && + p_elan->lec_state.c29_v2_capable) + return; /* TLV type was 0 with LANE2 => discard frame */ } la_config(p_elan->la_elan_handle, p_elan->lec_state.c2_lan_type, @@ -2819,7 +3179,8 @@ p_elan->lec_state.c18_forward_delay_time, p_elan->lec_state.c20_le_arp_response_time, p_elan->lec_state.c21_flush_timeout, - p_elan->lec_state.c22_path_switching_delay); + p_elan->lec_state.c22_path_switching_delay, + lane_version()); } sm_exec ((HANDLE) p_elan, E_RCV_CONFIG_RSP); } @@ -2868,6 +3229,25 @@ p_elan->lec_state.c14_lec_id = ntoh16 (frame->hdr.req_lec_id); + + /* LANE2: If LES is not v2 capable we can't be either */ + if (frame->hdr.flags & LE_FLAG_V2_REQUIRED && + p_elan->lec_state.c29_v2_capable == FALSE) { + EVENT (EM_NERR, ("LES requires LANEv2 but I'm not v2 capable\n")); + return; + } + if (!frame->hdr.flags & LE_FLAG_V2_REQUIRED) { /* LES not v2 */ + p_elan->lec_state.c29_v2_capable = FALSE; + p_elan->lec_state.c32_selective_mcast = FALSE; + } + /* Note: ELAN-ID and Local-Segment-ID TLVs are ignored + * since we do not use LLC-MUXED VCCs and know nothing + * about token ring + */ + if (frame->tlv_count != 0) + EVENT (EM_WARN, ("Got %d TLV(s), ignoring\n", frame->tlv_count)); + + /* Copy the joined ELAN type into our local state. */ switch (frame->lan_type) { @@ -2883,6 +3263,7 @@ case 2 : p_elan->lec_state.c3_lan_mtu = MTU_4544; break; case 3 : p_elan->lec_state.c3_lan_mtu = MTU_9234; break; case 4 : p_elan->lec_state.c3_lan_mtu = MTU_18190; break; + case 5 : p_elan->lec_state.c3_lan_mtu = MTU_1580; break; /* LANE2 */ default : return; } @@ -3035,9 +3416,12 @@ UINT32 length) { LE_ARP_FRAME *frame; + LE_ARP_FRAME *response; /* LANE2 */ STATUS status; UINT32 user_data; - + int sizeoftlvs; + size_t framelength; /* LANE2 */ + /* If the LEC control state machine is not in the operational state, simply * discard the receive packet. */ @@ -3049,32 +3433,54 @@ frame = (LE_ARP_FRAME*)p_packet; if (length < sizeof (LE_ARP_FRAME)) return; - + + framelength = sizeof(LE_ARP_FRAME) + p_elan->lec_state.sizeoftlvs; /* LANE2: Create new response frame */ + response = (LE_ARP_FRAME *)os_mem_alloc(framelength); + memset(response, 0, framelength); + memcpy(response, frame, sizeof(LE_ARP_FRAME)); + + sizeoftlvs = length - sizeof(LE_ARP_FRAME); + EVENT (EM_DEBUG, ("lec_arp_req: sizeoftlvs=%d\n", sizeoftlvs)); + switch (ntoh16 (frame->target_lan_dst.tag)) { - case TAG_NOT_PRESENT: + case TAG_NOT_PRESENT: /* LANE2: Targetless LE_ARP_REQUEST possible */ + if (p_elan->lec_state.c29_v2_capable) + la_arp_update (p_elan->la_elan_handle, + frame->src_lan_dst.mac_addr, + frame->src_atm_addr, + (ntoh16(frame->hdr.flags) & + LE_FLAG_REMOTE_ADDR) ? TRUE : FALSE, + (char *)frame + 1, + sizeoftlvs, + 1, /* LANE2, targetless LE_ARP */ + 0); /* LANE2, not no-source LE_NARP */ + break; case TAG_MAC_ADDR: if (lc_dest_is_registered ((HANDLE) p_elan, frame->target_lan_dst.mac_addr)) { - frame->hdr.op_code = hton16 (LE_ARP_RSP); - frame->hdr.status = hton16 (LE_STATUS_SUCCESS); - frame->hdr.flags = hton16 (0); /* Clear Remote Flag */ - ATM_COPY (p_elan->lec_state.c1_my_atm_addr, - frame->target_atm_addr); + response->hdr.op_code = hton16 (LE_ARP_RSP); + response->hdr.status = hton16 (LE_STATUS_SUCCESS); + response->hdr.flags = hton16 (0); /* Clear Remote Flag */ + ATM_COPY (p_elan->lec_state.c1n_my_atm_addr, response->target_atm_addr); + memcpy(response + 1, p_elan->lec_state.tlvs, p_elan->lec_state.sizeoftlvs); + if (p_elan->lec_state.sizeoftlvs != 0) frame->tlv_count++; user_data = USER_DATA_INTERNAL; status = cm_sap_xmt_vc (p_elan->ctrl_direct_conn_handle, - (void *) frame, - sizeof (LE_ARP_FRAME), + (void *) response, + framelength, user_data, NULL); - return; + break; } break; case TAG_ROUTE_DESC: break; - } + } /* switch */ + os_mem_dealloc(response); + return; } /*++ @@ -3092,6 +3498,7 @@ UINT32 length) { LE_ARP_FRAME *frame; + char *tmp = p_packet; int sizeoftlvs; frame = (LE_ARP_FRAME *)p_packet; @@ -3099,7 +3506,7 @@ if (length < sizeof (LE_ARP_FRAME)) return; sizeoftlvs = length - sizeof(LE_ARP_FRAME); - + tmp += sizeof(LE_ARP_FRAME); if (frame->hdr.status == ntoh16 (LE_STATUS_SUCCESS)) { switch (ntoh16 (frame->target_lan_dst.tag)) { case TAG_NOT_PRESENT: @@ -3121,13 +3528,16 @@ if (memcmp(p_elan->lec_state.c6_my_mac_addr.mac_addr, frame->target_lan_dst.mac_addr, sizeof(ESI))) { - la_arp_update (p_elan->la_elan_handle, - frame->target_lan_dst.mac_addr, - frame->target_atm_addr, - (ntoh16(frame->hdr.flags) & - LE_FLAG_REMOTE_ADDR) ? TRUE : FALSE, - (char *)frame + 1, - sizeoftlvs); + la_arp_update (p_elan->la_elan_handle, + frame->target_lan_dst.mac_addr, + frame->target_atm_addr, + (ntoh16(frame->hdr.flags) & + LE_FLAG_REMOTE_ADDR) ? TRUE : FALSE, + (char *)(frame + 1), + sizeoftlvs, + 0, /* LANE2, not targetless LE_ARP */ + 0); /* LANE2, not no-source LE_ARP */ + } } break; @@ -3158,10 +3568,10 @@ return; EVENT(EM_DEBUG,("Received flush request, my atmaddr:%s\n", - disp_atm_text(p_elan->lec_state.c1_my_atm_addr))); + disp_atm_text(p_elan->lec_state.c1n_my_atm_addr))); EVENT(EM_DEBUG,(" for :%s\n", disp_atm_text(frame->target_atm_addr))); - if (ATM_EQUAL (p_elan->lec_state.c1_my_atm_addr, frame->target_atm_addr)) { + if (ATM_EQUAL (p_elan->lec_state.c1n_my_atm_addr, frame->target_atm_addr)) { EVENT (EM_RDATA, ("Received Flush Request, Responding.\n")); frame->hdr.op_code = hton16 (LE_FLUSH_RSP); frame->hdr.status = hton16 (LE_STATUS_SUCCESS); @@ -3210,12 +3620,44 @@ * ================ * = lec_narp_req = * ================ +* +* LANE2 client must react to LE_NARP_REQUEST, see 7.1.35 --*/ STATIC void lec_narp_req (LC_ELAN_CONTEXT *p_elan, void *p_packet, UINT32 length) { + + LE_NARP_FRAME *frame = (LE_NARP_FRAME *)p_packet; + int sizeoftlvs, no_source; + char empty[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + EVENT (EM_RDATA, ("Received LE_NARP_REQUEST.\n")); + + if (length < sizeof(LE_NARP_FRAME)) + return; + + if (p_elan->sm_state != S_OPERATIONAL) + return; + + if ( (frame->hdr.status != ntoh16(LE_STATUS_SUCCESS)) || + (ntoh16(frame->hdr.req_lec_id) == p_elan->lec_state.c14_lec_id) ) + return; + + sizeoftlvs = length - sizeof(LE_NARP_FRAME); + no_source = ( memcmp(&frame->src_atm_addr, &empty, 20) == 0); /* true if source == 0 */ + if (p_elan->lec_state.c29_v2_capable) + la_arp_update (p_elan->la_elan_handle, + frame->src_lan_dst.mac_addr, + frame->src_atm_addr, + (ntoh16(frame->hdr.flags) & + LE_FLAG_REMOTE_ADDR) ? TRUE : FALSE, + (char *)frame + 1, + sizeoftlvs, + 0, /* LANE2, not targetless LE_ARP */ + no_source); + } /*++ diff -ur --new-file old/atm/led/lec_ctrl.h new/atm/led/lec_ctrl.h --- old/atm/led/lec_ctrl.h Wed Nov 19 12:59:15 1997 +++ new/atm/led/lec_ctrl.h Tue Aug 11 16:53:58 1998 @@ -98,6 +98,7 @@ #ifndef LEC_CTRL_H #define LEC_CTRL_H #include "cm_sap.h" +#include "lane2.h" /* LANE2 */ /************************************************************************* * Callbacks *************************************************************************/ @@ -283,7 +284,11 @@ BOOLEAN proxy_flag, HANDLE lport_handle, char *p_text, - HANDLE *p_lc_elan_handle); + HANDLE *p_lc_elan_handle, + BOOLEAN v2_capable, + ADDR_ATM preferred_les, + ADDR_L3 l3_address, + const char *foreId); /* Info string displayed by Fore switches */ /*++ diff -ur --new-file old/atm/led/main.c new/atm/led/main.c --- old/atm/led/main.c Sun Feb 1 13:23:06 1998 +++ new/atm/led/main.c Tue Aug 11 16:53:58 1998 @@ -56,6 +56,7 @@ #include "conn.h" #include "timers.h" #include "kernel_itf.h" +#include "lane2.h" /* LD_ELAN_CONTEXT * Context block for a single ELAN membership. An instance of this structure @@ -131,10 +132,13 @@ int stay_alive =1; int reset=0; +static int spec_version = 1; /* By default act like LANE v1 device */ #define EMOD MOD_LEC_DATA #define EINST "main.c" +#define FORE_ID_LEN 256 + /* Mask for messages, include emask.h */ UINT32 EMASK = (EM_SERR | EM_NERR | EM_WARN | EM_MSG); @@ -164,6 +168,11 @@ reset = 1; } +int lane_version(void) +{ + return spec_version; +} + static void elan_status_callback(HANDLE elan_handle, BOOLEAN elan_available, LAN_MTU lan_mtu, char *p_elan_name, @@ -175,7 +184,7 @@ elan = (LD_ELAN_CONTEXT *)elan_handle; elan->lec_id = lec_id; - kernel_sendmsg(l_set_lecid, NULL, NULL, NULL, lec_id, NULL, 0); + kernel_sendmsg(l_set_lecid, NULL, NULL, NULL, lec_id, NULL, 0, 0, 0); } void @@ -261,7 +270,7 @@ { printf("Usage: %s [-c LECS_address]|[-s LES_address] [-e esi] [-n VLAN_name]" " [-m mesg_mask] [-l listen_address] [-i interface_number]" - " [-q qos_spec]\n",progname); + " [-q qos_spec] [-1] [-2] [-f Fore specific name]\n", progname); } static int @@ -340,7 +349,10 @@ BOOLEAN proxy_flag = FALSE; HANDLE lport_handle = NULL; char p_text[] = "Lec Control Unit"; - + BOOLEAN v2_capable = FALSE; /* LANE2 stuff follows */ + ADDR_ATM preferred_les; + ADDR_L3 l3_address = 0; + LD_CONTEXT *p_context; LD_ELAN_CONTEXT *p_elan; STATUS status; @@ -353,9 +365,12 @@ ADDR_ATM *listen_address = NULL; int itf_num = 0; const char *qos_spec = NULL; + char foreId[FORE_ID_LEN]; + memset(foreId, '\0', FORE_ID_LEN); + memset(&preferred_les, 0, sizeof(ADDR_ATM)); while(poll_ret != -1) { - poll_ret = getopt(argc, argv, "c:e:n:s:m:l:i:q:"); + poll_ret = getopt(argc, argv, "c:e:n:s:m:l:i:q:12f:"); switch(poll_ret) { case 'c': if (atm_set) { @@ -431,6 +446,19 @@ } qos_spec = optarg; break; + case '1': + spec_version = 1; + break; + case '2': + spec_version = 2; + v2_capable = TRUE; + break; + case 'f': + memcpy (foreId, optarg, FORE_ID_LEN); + foreId[FORE_ID_LEN-1] = '\0'; + EVENT(EM_MSG, ("foreId :'%s'\n", foreId)); + printf("foreId '%s'\n", foreId); + break; case -1: break; default: @@ -524,7 +552,11 @@ proxy_flag, lport_handle, p_text, - &p_elan->lc_elan_handle); + &p_elan->lc_elan_handle, + v2_capable, + preferred_les, + l3_address, + foreId); if (status != STATUS_K_SUCCESS) { EVENT (EM_SERR, ("Failed to register lec_ctrl instance.\n")); os_mem_dealloc (p_elan); diff -ur --new-file old/atm/led/zeppelin.8 new/atm/led/zeppelin.8 --- old/atm/led/zeppelin.8 Wed Nov 19 12:59:16 1997 +++ new/atm/led/zeppelin.8 Tue Aug 11 16:53:58 1998 @@ -1,4 +1,4 @@ -.TH zeppelin 8 "Nov 11, 1996" "Linux" "Maintenance Commands" +.TH zeppelin 8 "Jul 29, 1998" "Linux" "Maintenance Commands" .SH NAME zeppelin \- ATM LAN Emulation client demon (LED) Zeppelin .SH SYNOPSIS @@ -29,7 +29,6 @@ \fBSIGHUP\fP causes restart of the LEC. All resources are released and \fBzeppelin\fP is started. .SH OPTIONS -.TP .IP \fB\-c\ \fILECS_address\fP ATM address of \fBlecs(8)\fP (Lan Emulation Configuration Server), if not set, Well-Known server address is used. @@ -55,9 +54,14 @@ Linux LEC supports up to 4 network interfaces. This number tells zeppelin to which of these to attach. Network interfaces are numbered from "lec0" to "lec3". -.IP \fB\-i\ \fIqos_spec\fP -Set the specified quality of service (see qos(7) for the syntax) for outgoing -calls. UBR at link speed is used by default. +.IP \fB\-1\fP +Run as LANEv1 client. This is the default. +.IP \fB\-2\fP +Run as LANEv2 client. This is required by MPOA. +.IP \fB\-f\ \fIFore\ specific\ name\fP +The LANE servers on Fore ATM switches can display a special +name if a client can supply one. This name shows with command +\'conf lane les show advanced\'. .SH BUGS Supports only IEEE 802.3 / Ethernet type of ELANs. .PP @@ -65,5 +69,5 @@ .SH AUTHOR Marko Kiiskila, TUT .SH "SEE ALSO" -lecs(8), atmsigd(8), les(8), qos(7) +lecs(8), mpcd(8), atmsigd(8), les(8), qos(7) .\"{{{}}} diff -ur --new-file old/atm/mkdist new/atm/mkdist --- old/atm/mkdist Fri Jul 24 15:19:01 1998 +++ new/atm/mkdist Tue Aug 11 19:40:26 1998 @@ -90,6 +90,7 @@ atm/led/conn.h atm/led/lec_arp.c atm/led/lec_ctrl.c \ atm/led/le_disp.c atm/led/g_event.c atm/led/utils.c atm/led/timers.c \ atm/led/address.c atm/led/conn.c atm/led/main.c atm/led/kernel_itf.c \ + atm/led/lane2.h \ atm/led/Makefile atm/led/zeppelin.8 \ atm/lane/COPYRIGHT.TUT atm/lane/Makefile atm/lane/USAGE \ atm/lane/bus.8 atm/lane/lecs.8 atm/lane/les.8 \ @@ -105,6 +106,11 @@ atm/lane/mem_lecs.c atm/lane/mem_lecs.h atm/lane/packet.c \ atm/lane/packet.h atm/lane/timers.h atm/lane/timers.c atm/lane/units.c \ atm/lane/units.h \ + atm/mpoad/Makefile atm/mpoad/README.mpoa atm/mpoad/TODO atm/mpoad/get_vars.c \ + atm/mpoad/get_vars.h atm/mpoad/id_list.c atm/mpoad/io.c atm/mpoad/io.h \ + atm/mpoad/k_interf.c atm/mpoad/k_interf.h atm/mpoad/main.c \ + atm/mpoad/mpcd.8 atm/mpoad/p_factory.c atm/mpoad/p_recogn.c \ + atm/mpoad/packets.h atm/mpoad/tag_list.c \ atm/aqd/Makefile atm/aqd/arequipad.c atm/aqd/io.h atm/aqd/io.c \ atm/aqd/arequipad.8 atm/aqd/aqpvc.c atm/aqd/aqpvc.8 \ atm/switch/Makefile atm/switch/Rules.make atm/switch/cfg.l atm/switch/cfg.y \ diff -ur --new-file old/atm/mpoad/Makefile new/atm/mpoad/Makefile --- old/atm/mpoad/Makefile Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/Makefile Thu Jul 2 11:14:30 1998 @@ -0,0 +1,9 @@ +LIBS=-latm +OBJS=get_vars.o io.o k_interf.o main.o p_factory.o p_recogn.o id_list.o tag_list.o +BOOTPGMS=mpcd +MAN8= mpcd.8 + +include ../Rules.make + +mpcd: $(OBJS) + $(CC) $(LDFLAGS) -o mpcd $(OBJS) $(LIBD) $(LDLIBS) diff -ur --new-file old/atm/mpoad/README.mpoa new/atm/mpoad/README.mpoa --- old/atm/mpoad/README.mpoa Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/README.mpoa Fri Aug 7 16:24:57 1998 @@ -0,0 +1,51 @@ +August 7 1998 + +This is the first version of MPOA client for Linux. In order to run +MPOA you need to have LANE client (zeppelin) running too. Below is a +snippet from our boot-up script which starts LANE and MPOA. + +case "$1" in + start) + cd $ATM + if [ -x sigd/atmsigd ] ; then + sigd/atmsigd -b + fi + if [ -x ilmid/ilmid ] ; then + ilmid/ilmid -b -x + fi + if [ -x led/zeppelin ] ; then + led/zeppelin -f "Linux 2.1.105/ATM-0.39" -2 -c mpoa-lecs -n sampo -i2 -l jaarlimpc3 & + sleep 2 + ifconfig lec2 10.10.10.208 \ + netmask 255.255.255.192 \ + broadcast 10.10.10.255 + ifconfig lec2 up + route add default gw 10.10.10.193 + fi + sleep 5 + if [ -x mpoad/mpcd ] ; then + mpoad/mpcd -i2 -s jaarlimpc1 -l jaarlimpc2 -m 0000ef06a140 & + fi + ;; +esac + +exit 0 + +Things worth noting are: + o same interface number (2) for zeppelin and mpcd + o different local ATM addresses (jaarlimpc[123]) + o -2 option for zeppelin to get it running as a LANEv2 client + o default gw being reached via MPOA-enabled LANE interface. + +The MAC address of our router was given by hand because it did not +advertise it's MAC address via MPOA device discovery. + +Shortcuts, shortcut states and packet counters are available in +/proc/mpoa/mpc_stats. + +If you are running your LANE services on a Fore switch, you can try +the '-f' option for zeppelin. My favourite is -f "`fortune`" :) + +Sampo Saaristo +Heikki Vatiainen + diff -ur --new-file old/atm/mpoad/TODO new/atm/mpoad/TODO --- old/atm/mpoad/TODO Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/TODO Fri Aug 7 16:18:59 1998 @@ -0,0 +1,7 @@ +Check that closing unused SVCs does not create synchronization problems + +Move /proc/mpoa/mpc_stats to /proc/atm/ + +MPOA spec, A.1.4, IP Options, check them + +Support more MPOA/NHRP CIE error codes diff -ur --new-file old/atm/mpoad/get_vars.c new/atm/mpoad/get_vars.c --- old/atm/mpoad/get_vars.c Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/get_vars.c Tue Aug 11 17:43:52 1998 @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "get_vars.h" +#include "io.h" + +extern struct sockaddr_atmsvc data_listen_addr; /* From main.c */ + +/* Returns the Time To Live value. */ +int get_ttl(){ + int optvalue = 1; + unsigned optlength = sizeof(optvalue); + int sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ); + getsockopt( sockfd, IPPROTO_IP, IP_TTL, &optvalue, &optlength ); + close(sockfd); + return optvalue; +} + +/* + * Returns clients own IP-address. According to interface number. + * + */ +uint32_t get_own_ip_addr(int iface_nmbr ){ + struct ifreq req; + int fd; + char * addr; + uint32_t address; + char name[6]; + sprintf(name, "lec%d", iface_nmbr ); + memcpy(req.ifr_ifrn.ifrn_name,name,sizeof(name)); + fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ); + if(fd < 0){ + printf("mpcd: get_vars.c: socket creation failed.\n"); + exit(1); + } + if(ioctl(fd,SIOCGIFADDR,&req)<0){ + printf("mpcd: get_vars.c: ioctl failed: %s\n", strerror(errno)); + exit(1); + } + addr = req.ifr_ifru.ifru_addr.sa_data; + address = ((unsigned char)addr[2] << 24) | + ((unsigned char)addr[3] << 16) | + ((unsigned char)addr[4] << 8 ) | + (unsigned char)addr[5] ; + close(fd); + return address; +} + + +/* + * Sets our ATM address to be used in control packets. + * This get's called if the address is not given as a parameter + * while starting MPC daemon. + * + */ +int set_own_atm_addr(unsigned char address[20]){ + struct sockaddr_atmsvc sa; + struct atmif_sioc req; + int fd = get_socket(NULL); + int selector; + req.number=0; + req.arg=&sa; + req.length=sizeof(struct sockaddr_atmsvc); + if ( ioctl(fd, ATM_GETADDR, &req) <0 ){ + printf("mpcd: get_vars.c: ioctl error \n"); + return 0; + } + address[0] = sa.sas_addr.prv[0]; + address[1] = sa.sas_addr.prv[1]; + address[2] = sa.sas_addr.prv[2]; + address[3] = sa.sas_addr.prv[3]; + address[4] = sa.sas_addr.prv[4]; + address[5] = sa.sas_addr.prv[5]; + address[6] = sa.sas_addr.prv[6]; + address[7] = sa.sas_addr.prv[7]; + address[8] = sa.sas_addr.prv[8]; + address[9] = sa.sas_addr.prv[9]; + address[10] = sa.sas_addr.prv[10]; + address[11] = sa.sas_addr.prv[11]; + address[12] = sa.sas_addr.prv[12]; + address[13] = sa.sas_addr.prv[13]; + address[14] = sa.sas_addr.prv[14]; + address[15] = sa.sas_addr.prv[15]; + address[16] = sa.sas_addr.prv[16]; + address[17] = sa.sas_addr.prv[17]; + address[18] = sa.sas_addr.prv[18]; + address[19] = sa.sas_addr.prv[19]; + address[20] = sa.sas_addr.prv[20]; + /* Loop until a free selector byte is found. */ + selector = atoi(&sa.sas_addr.prv[20]); + while(bind(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_atmsvc))<0){ + printf("mpcd: get_vars.c: %s\n",strerror(errno)); + selector++; + if(selector>254){ + printf("mpcd: get_vars.c: could not set own atm address.\n"); + exit(1); + } + sprintf(&address[20],"%d",selector); + sprintf(&sa.sas_addr.prv[20],"%d",selector); + } + printf("mpcd: get_vars.c: selector set to %d \n",selector); + close(fd); + return 1; +} + +int get_own_atm_addr(unsigned char * address){ + memcpy(address,data_listen_addr.sas_addr.prv,ATM_ESA_LEN); + return 1; +} + + + + + + + diff -ur --new-file old/atm/mpoad/get_vars.h new/atm/mpoad/get_vars.h --- old/atm/mpoad/get_vars.h Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/get_vars.h Thu Jun 18 13:24:53 1998 @@ -0,0 +1,12 @@ +#ifndef GET_VARS_H +#define GET_VARS_H + +#include + +int get_ttl(void); +uint32_t get_own_ip_addr(int iface_nmbr); +int set_own_atm_addr(unsigned char *address ); +int get_own_atm_addr(unsigned char *address ); + +#endif /* GET_VARS_H */ + diff -ur --new-file old/atm/mpoad/id_list.c new/atm/mpoad/id_list.c --- old/atm/mpoad/id_list.c Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/id_list.c Fri Aug 7 15:02:42 1998 @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include "packets.h" + +struct rqst_id{ + struct rqst_id *next; + struct rqst_id *prev; + uint32_t request_id; + uint32_t cache_id; + uint8_t type; + time_t created; +}; + +static struct rqst_id *ids = NULL; /* pointer to first item in id list*/ + +/* + * Searches the list according to request id. + * + */ +static struct rqst_id *search_by_id(uint32_t id){ + struct rqst_id *pid = ids; + while(pid != NULL){ + if(id == pid->request_id) + return pid; + pid = pid->next; + } + return NULL; +} + +/* + * Searches the list accoring to type and cache_id. + * Refreshes the created time of the list item if found. + * Returns a request_id on success. + * + */ +uint32_t search_by_type(uint8_t type, uint32_t cache_id){ + struct rqst_id *pid = ids; + while(pid != NULL){ + if(type == pid->type){ + if(pid->cache_id == cache_id){ + pid->created = time(NULL); + return pid->request_id; + } + } + pid = pid->next; + } + return 0; +} + +/* + * Creates a new id and adds it to list. + * + */ +int new_id(uint32_t id, uint32_t cache_id, uint8_t type){ + struct rqst_id *new; + if( search_by_id(id) != NULL ) + return 0; + new = malloc(sizeof(struct rqst_id)); + memset(new,0,sizeof(struct rqst_id)); + new->request_id = id; + new->cache_id = cache_id; + new->type = type; + new->created = time(NULL); + new->next = ids; + new->prev = NULL; + if(ids != NULL) + ids->prev = new; + ids = new; + return 1; +} + +/* + * Removes an id from the list and frees the allocated memory + * + */ +static int remove_id(struct rqst_id *pid){ + printf("mpcd: id_list.c: removing id %u from the id_list.\n",pid->request_id); + if(pid == NULL) + return 0; + if(pid->prev != NULL) + pid->prev->next = pid->next; + else + ids = pid->next; + if(pid->next != NULL) + pid->next->prev = pid->prev; + free(pid); + return 1; +} + +/* + * Removes ids that have stayed longer than ID_EXPIRING_TIME + * from the list. + * + */ +void clear_expired(){ + static int call_count=0; + struct rqst_id *pid = ids; + struct rqst_id *next_pid; + time_t now = time(NULL); + call_count++; + if(call_count%5 != 0) + return; + while(pid != NULL){ + next_pid = pid->next; + if(now - pid->created > ID_EXPIRING_TIME) + remove_id(pid); + pid = next_pid; + } + call_count = 0; +} + +/* + * Checks whether we have sent a request with id returned in a reply + * and that the reply is of right type. + * + */ +int check_incoming(uint32_t id, uint8_t type){ + struct rqst_id *pid = search_by_id(id); + if( pid == NULL ){ + printf("mpcd: id_list.c: no request sent with request_id %d\n",id); + return 0; + } + if( pid->type != type){ + printf("mpcd: id_list.c: matching request_id found, but packet type is invalid %d\n",type); + return 0; + } + remove_id(pid); + return 1; +} + diff -ur --new-file old/atm/mpoad/io.c new/atm/mpoad/io.c --- old/atm/mpoad/io.c Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/io.c Wed Aug 12 18:10:15 1998 @@ -0,0 +1,688 @@ +#include +#include +#include /* for time() */ +#include +#include /* for strerror() */ +#include +#include +#include /* for OPEN_MAX */ +#if __GLIBC__ >= 2 +#include +#else /* ugly hack to make it compile on RH 4.2 - WA */ +#include +#include +#define SYS_poll 168 +_syscall3(int,poll,struct pollfd *,ufds,unsigned int,nfds,int,timeout); +#endif +#include +#include +#include +#include +#include +#include +#include /* for ntohl() */ + +#include "packets.h" +#include "k_interf.h" +#include "io.h" +#include "get_vars.h" + +#define POLL_TIMEOUT 5000 /* poll() timeout, 5 seconds */ + +#if 1 +#define dprintf printf +#else +#define dprintf(format,args...) +#endif + +#if 0 +#define ddprintf printf +#else +#define ddprintf(format,args...) +#endif + +extern int INTERFACE_NUMBER; /* from main.c */ + +int keep_alive_sm_running = 0; + +struct outgoing_shortcut { + int fd; + uint32_t ipaddr; /* in network byte order */ + int state; /* see io.h for states */ +}; + +static struct llc_snap_hdr llc_snap_mpoa_ctrl = { + 0xaa, 0xaa, 0x03, + {0x00, 0x00, 0x5e}, + {0x00, 0x03} +}; + +extern int kernel_socket; /* kernel socket for mpcd <--> kernel msgs, from main.c */ +extern int MPS_socket; /* MPS control socket for out going msgs, from main.c */ +extern int MPS_listen_socket; /* MPS control listen socket, from main.c */ +extern unsigned char MPS_CTRL_ATM_ADDR[]; +extern unsigned char OWN_ATM_ADDRESS[]; +extern struct sockaddr_atmsvc data_listen_addr; + +extern int mps_ctrl_addr_set; +static time_t stay_alive; /* Next Keep-Alive should come before we hit this time */ +static struct pollfd fds[OPEN_MAX]; +static int first_empty; /* first non-reserved slot in fds[] */ +static int fds_used; /* first non-occupied slot in fds[] */ +static short socket_type[OPEN_MAX]; /* type and state info for fds[], see "io.h" for types */ +static struct outgoing_shortcut ingress_shortcuts[OPEN_MAX]; /* array of shortcuts we made */ + +static int update_ingress_entry(uint32_t *addr, int fd, int new_state); +static int msg_from_mps(int slot); +static int accept_conn(int slot); +static int add_shortcut(int slot, int type); +static int check_connection(int slot); +static int complete_connection(int slot); +static int create_shortcut(char *atm_addr); +static void wait_for_mps_ctrl_addr(void); +static int connect_to_MPS(void); + +void main_loop(int listen_socket) +{ + int i, changed_fds; + int kernel_ok, mps_ok, new_ctrl, new_shortcut; + int poll_timeout = POLL_TIMEOUT; + time_t now, previous_now; + for (i = 0; i < OPEN_MAX; i++) + fds[i].fd = -1; + + fds[0].fd = kernel_socket; /* mpcd <--> kernel socket */ + fds[0].events = POLLIN; + socket_type[0]= KERNEL; + + if(!mps_ctrl_addr_set) /* Can't do much without the MPS control ATM addr */ + wait_for_mps_ctrl_addr(); + connect_to_MPS(); + + fds[1].fd = MPS_socket; /* we opened this to MPS */ + fds[1].events = POLLIN; + socket_type[1]= (OUTGOING_CTRL | CONNECTED); + fds[2].fd = MPS_listen_socket; /* for incoming control calls */ + fds[2].events = POLLIN; + socket_type[2]= LISTENING_CTRL; + fds[3].fd = listen_socket; /* for incoming shortcuts */ + fds[3].events = POLLIN; + socket_type[3]= LISTENING_DATA; + fds_used = first_empty = 4; + now = previous_now = time(NULL); + + while (1) { + kernel_ok = mps_ok = new_ctrl = new_shortcut = 1; + fflush(stdout); + changed_fds = poll(fds, OPEN_MAX, poll_timeout); +#if 0 + changed_fds = poll(fds, fds_used + 1, poll_timeout); +#endif + switch(changed_fds) { + case -1: + printf("mpcd: io.c: main_loop: poll error: %s\n", strerror(errno)); + if(errno == EINTR) continue; + exit (1); + break; /* not reached */ + case 0: + keep_alive_sm(0, -1); /* (keepalive_liftime, seq_num) */ + clear_expired(); /* id_list.c */ + poll_timeout = POLL_TIMEOUT; + previous_now = time(NULL); + continue; + break; /* not reached */ + } + + /* It was not a timeout. Adjust poll_timeout */ + now = time(NULL); + poll_timeout -= now - previous_now; + if (poll_timeout < 0) poll_timeout = 0; + + /* Since we are here something happened to the fds */ + if (fds[0].revents) { + kernel_ok = msg_from_kernel(fds[0].fd); + dprintf("mpcd: io.c: main_loop() msg_from_kernel\n"); + --changed_fds; + } + if (fds[1].revents) { + mps_ok = msg_from_mps(1); + ddprintf("mpcd: io.c: main_loop() msg_from_mps1\n"); + --changed_fds; + } + if (fds[2].revents) { + new_ctrl = accept_conn(2); + socket_type[new_ctrl] = INCOMING_CTRL | CONNECTED; + dprintf("mpcd: io.c main:_loop() accepted INCOMING_CTRL fd =%d\n", new_ctrl); + --changed_fds; + } + if (fds[3].revents) { + new_shortcut = accept_conn(3); + dprintf("mpcd: io.c main:_loop() accepted INCOMING_SHORTCUT fd =%d\n", new_shortcut); + socket_type[new_shortcut] = INCOMING_SHORTCUT; + if (add_shortcut(new_shortcut, MPC_SOCKET_EGRESS) < 0) + break; + --changed_fds; + } + + if (changed_fds == 0) /* see if we can already go back to poll() */ + continue; + + for (i = first_empty; i <= fds_used; i++) { + if (fds[i].fd < 0 || fds[i].revents == 0) + continue; /* not used or unchanged */ + if (socket_type[i] & INCOMING_CTRL) { + mps_ok = msg_from_mps(i); + ddprintf("mpcd: io.c: main_loop() msg_from_mps2\n"); + } + else if (check_connection(i) < 0) + break; /* this will cause break from while(1) too */ + if (--changed_fds == 0) + break; /* leave for() */ + } + + if (changed_fds != 0){ + dprintf("mpcd: changed_fds = %d\n", changed_fds); + break; /* leave while(1) */ + } + if (kernel_ok && mps_ok >= 0 && new_ctrl >= 0 && new_shortcut >= 0) + continue; /* back to poll() */ + // break; + } + + /* clean up, close the sockets */ + for (i = 0; i < fds_used; i++) { + if (fds[i].fd < 0) + continue; + close(fds[i].fd); + socket_type[i] = NOT_USED; + } + printf("mpcd: io.c: exiting main_loop()\n"); + return; +} + +/* + * If MPS control ATM address is not given as an argument this func waits until + * kernel has found one from a TLV in le_arp and tells us what it is. + */ +static void wait_for_mps_ctrl_addr(){ + while(!mps_ctrl_addr_set){ + if(poll(fds, 1, -1)) + msg_from_kernel(fds[0].fd); + } + return; +} + + + +/* + * Sends a packet to MPS. Adds LLC/SNAP encapsulation + * in the beginning of the buffer. + */ +int send_to_mps(char *buff, int length) +{ + char tmp[MAX_PACKET_LENGTH + sizeof(struct llc_snap_hdr)]; + int bytes_written; + char *pos = tmp; + if(MPS_socket<0){ + connect_to_MPS(); + fds[1].fd = MPS_socket; + fds[1].events = POLLIN; + socket_type[1] = (OUTGOING_CTRL | CONNECTED); + } + memcpy(pos, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)); + pos += sizeof(struct llc_snap_hdr); + memcpy(pos, buff, length); + length += sizeof(struct llc_snap_hdr); + bytes_written = write(MPS_socket, tmp, length); + while(bytes_written != 0){ + bytes_written = write(MPS_socket, tmp+bytes_written, length-bytes_written); + if( bytes_written < 0 ){ + printf("mpcd: io.c: write failed."); + return -1; + } + } + return 1; +} + +/* + * Sends a control packet over a shortcut. Used in a dataplane purge. + */ +int send_to_dataplane(char *buff, int length, int shortcut_fd) +{ + char tmp[MAX_PACKET_LENGTH + sizeof(struct llc_snap_hdr)]; + int bytes_written; + char *pos = tmp; + memcpy(pos, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)); + pos += sizeof(struct llc_snap_hdr); + memcpy(pos, buff, length); + length += sizeof(struct llc_snap_hdr); + bytes_written = write(shortcut_fd, tmp, length); + while(bytes_written != 0){ + bytes_written = write(shortcut_fd, tmp+bytes_written, length-bytes_written); + if( bytes_written < 0 ){ + printf("mpcd: io.c: write to dataplane failed."); + return -1; + } + } + return 1; +} + +/* + * Keep alive state machine. Sequence number less than + * and keep_alive_lifetime equal to zero is used + * when checking wheter the MPS is still alive. + * + */ +void keep_alive_sm(unsigned keep_alive_lifetime, int sequence_number){ + struct k_message msg; + static unsigned previous_sequence_number = 0; + static start_keep_alive_sm = 0; + time_t now = time(NULL); + memset(&msg,0,sizeof(struct k_message)); + if(!keep_alive_sm_running){ + start_keep_alive_sm = 0; + return; + } + if(!start_keep_alive_sm){ + dprintf("mpcd: io.c: starting keep_alive_sm.\n"); + stay_alive = time(NULL) + MPC_C2; + start_keep_alive_sm = 1; + return; + } + if( now > stay_alive ){ + dprintf("mpcd: io.c: MPS death!"); + msg.type = MPS_DEATH; + memcpy(msg.MPS_ctrl,MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); + send_to_kernel(&msg); + previous_sequence_number = 0; + stay_alive = now + MPC_C2; + return; + } + if( sequence_number < 0 ) + return; + if( sequence_number < previous_sequence_number ){ + dprintf("mpcd: io.c: MPS death!"); + msg.type = MPS_DEATH; + memcpy(msg.MPS_ctrl,MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); + send_to_kernel(&msg); + previous_sequence_number = 0; + stay_alive = now + MPC_C2; + return; + } + stay_alive = now + keep_alive_lifetime; + previous_sequence_number = sequence_number; + return; +} + +/* + * Creates a socket, sets traffic and sap parameters + * and binds the socket with given address. + * + * returns < 0 for error, socket for ok + */ +int get_socket(struct sockaddr_atmsvc *address) +{ + struct atm_qos qos; + struct atm_sap sap; + int socket_fd; + + socket_fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); + if( socket_fd < 0 ){ + printf("mpcd: io.c: socket creation failure: %s \n",strerror(errno)); + return -1; + } + memset(&qos, 0, sizeof(qos)); + memset(&sap, 0, sizeof(sap)); + qos.aal = ATM_AAL5; + qos.txtp.traffic_class = ATM_UBR; + qos.rxtp.traffic_class = ATM_UBR; + qos.txtp.max_sdu = 1536; + qos.rxtp.max_sdu = 1536; + sap.blli[0].l2_proto = ATM_L2_ISO8802; + if (setsockopt(socket_fd, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ + printf("mpcd: io.c: setsockopt SO_ATMQOS failed: %s \n",strerror(errno)); + close(socket_fd); + return -1; + } + if (setsockopt(socket_fd,SOL_ATM,SO_ATMSAP,&sap,sizeof(sap)) < 0) { + printf("mpcd: io.c: setsockop SO_ATMSAP failed\n"); + close (socket_fd); + return -1; + } + if (address == NULL) + return socket_fd; + if (bind(socket_fd, (struct sockaddr *)address, sizeof(struct sockaddr_atmsvc)) < 0){ + printf("mpcd: io.c: bind failure: %s \n",strerror(errno)); + close(socket_fd); + return -1; + } + return socket_fd; +} + +/* + * If addr != NULL searches by addr. If addr == NULL searches by fd. + * Returns ipaddr. + * + */ +static int update_ingress_entry(uint32_t *addr, int fd, int new_state) +{ + int i; + + if (addr != NULL) { + dprintf("mpcd: io.c update_ingress_entry() updating ip 0x%x\n", *addr); + for (i = 0; i < OPEN_MAX; i++) + if (ingress_shortcuts[i].ipaddr == *addr) + break; + } + else { + dprintf("mpcd: io.c update_ingress_entry() updating fd %d\n", fd); + for (i = 0; i < OPEN_MAX; i++) + if (ingress_shortcuts[i].fd == fd) + break; + } + if (i == OPEN_MAX) { + printf("mpcd: io.c: update_ingress_entry: entry not found\n"); + return 0; + } + ingress_shortcuts[i].fd = fd; + ingress_shortcuts[i].state = new_state; + if (new_state == INGRESS_NOT_USED) + memset(&ingress_shortcuts[i], 0 , sizeof(ingress_shortcuts[i])); + + return ingress_shortcuts[i].ipaddr; +} + +/* + * returns < 0 for error + * + */ +static int msg_from_mps(int slot) +{ + int bytes_read, fd; + char buff[MAX_PACKET_LENGTH]; + + fd = fds[slot].fd; + bytes_read = read(fd, buff, sizeof(buff)); + if (bytes_read < 0) { + printf("mpcd: io.c: read failed from MPS: %s\n", strerror(errno)); + close(fd); + fds[slot].fd = -1; + socket_type[slot] = NOT_USED; + return -1; + } + if (bytes_read == 0) { + dprintf("mpcd: io.c: EOF from MPS\n"); + close(fd); + fds[slot].fd = -1; + if (slot == 1) + MPS_socket = -1; + socket_type[slot] = NOT_USED; + return 1; /* See spec 4.6. Might be normal */ + } + + if ( memcmp(buff, &llc_snap_mpoa_ctrl, sizeof(llc_snap_mpoa_ctrl)) != 0 ) { + printf("mpcd: io.c: msg_from_mps: MPS is pushing us garbage\n"); + return -1; + } + + (void)recognize_packet(buff + sizeof(struct llc_snap_hdr)); + + return 0; +} + +/* + * returns < 0 for error, slot of the new socket for ok + * + */ +static int accept_conn(int slot) +{ + struct sockaddr_atmsvc sa; + int i, new_fd, sa_len; + + sa_len = sizeof(sa); + new_fd = accept(fds[slot].fd, (struct sockaddr *)&sa, &sa_len); + if (new_fd < 0) { + printf("mpcd: io.c: accept_conn: %s\n", strerror(errno)); + return -1; + } + + for (i = first_empty; i < OPEN_MAX; i++) { + if (fds[i].fd >= 0) /* slot in use ? */ + continue; + fds[i].fd = new_fd; + fds[i].events = POLLIN; + break; + } + if (i == OPEN_MAX) { + printf("mpcd: io.c: do_accept: no room for new connection\n"); + return -1; + } + + if (i > fds_used) + fds_used = i; + + return i; +} + +/* + * returns < 0 for error, slot of the new socket for ok + * + */ +static int add_shortcut(int slot, int type) +{ + struct atmmpc_ioc ioc_data; + int ipaddr = 0; + + if (type == MPC_SOCKET_INGRESS) + ipaddr = update_ingress_entry(NULL, fds[slot].fd, INGRESS_CONNECTED); + + ioc_data.dev_num = INTERFACE_NUMBER; + ioc_data.ipaddr = ipaddr; + ioc_data.type = type; + if (ioctl(fds[slot].fd, ATMMPC_DATA, &ioc_data) < 0) { + printf("mpcd: io.c: add_shortcut: %s\n", strerror(errno)); + close(fds[slot].fd); + fds[slot].fd = -1; + socket_type[slot] = NOT_USED; + return -1; + } + + return slot; +} + +/* + * ECONNRESET == RST in TCP world. Check what equivalent + * events can happen in ATM world. + * + * Returns < 0 for error + */ +static int check_connection(int slot) +{ + char buff[MAX_PACKET_LENGTH]; + struct k_message *msg; + struct pollfd *pfd; + int bytes_read; + + dprintf("mpcd: io.c: check_connection() event in fd %d, type %d\n", fds[slot].fd, socket_type[slot]); + pfd = &fds[slot]; + if (socket_type[slot] & CONNECTING) /* connect() completed (maybe) */ + return complete_connection(slot); + + bytes_read = read(pfd->fd, buff, sizeof(buff)); + if (bytes_read < 0) { + if (errno == ECONNRESET || errno == EPIPE) { /* conn reset by the other end or kernel (EPIPE) */ + if (socket_type[slot] & OUTGOING_SHORTCUT) + update_ingress_entry(NULL, pfd->fd, INGRESS_NOT_USED); + + close(pfd->fd); + pfd->fd = -1; + socket_type[slot] = NOT_USED; + return 1; + } + printf("mpcd: io.c: check_connection() bytes_read=%d, errno='%s'\n", bytes_read, strerror(errno)); + return -1; + } + if (bytes_read == 0) { /* conn closed by the other end */ + if (socket_type[slot] & OUTGOING_SHORTCUT) + update_ingress_entry(NULL, pfd->fd, INGRESS_NOT_USED); + + dprintf("mpcd: io.c: check_connection() fd %d type %d; connection closed'\n", pfd->fd, socket_type[slot]); + close(pfd->fd); + pfd->fd = -1; + socket_type[slot] = NOT_USED; + return 1; + } + + /* See if this is a MPOA control packet */ + if ( memcmp(buff, &llc_snap_mpoa_ctrl, sizeof(llc_snap_mpoa_ctrl)) == 0 ) + if ( recognize_packet(buff + sizeof(llc_snap_mpoa_ctrl)) >= 0) + return 1; + + dprintf("mpcd: io.c check_connection(): msg from kernel\n"); + msg = (struct k_message *)buff; + if(msg->type == DATA_PLANE_PURGE){ + send_purge_request(msg->content.eg_info.mps_ip,32, + get_own_ip_addr(INTERFACE_NUMBER),pfd->fd); + return 1; + } + + printf("mpcd: io.c check_connection(): unknown msg %d from kernel, ignoring", + msg->type); + + return 1; +} + +/* + * returns < 0 for error, socket for ok + * + */ +static int complete_connection(int slot) +{ + int retval; + struct sockaddr_atmsvc dummy; + + dprintf("mpcd: io.c: complete_connection() completing fd %d slot %d\n", fds[slot].fd, slot); + /* this seems to be common method in Linux-ATM + * making sure that nonblocking connect was + * completed successfully + */ + retval = connect(fds[slot].fd,(struct sockaddr *)&dummy, sizeof(dummy)); + if (retval != 0) + return -1; + socket_type[slot] &= ~CONNECTING; + socket_type[slot] |= CONNECTED; + + fds[slot].events = POLLIN; /* We left POLLOUT accidentally in. Hope you never do the same */ + if(socket_type[slot] & OUTGOING_SHORTCUT) + return add_shortcut(slot, MPC_SOCKET_INGRESS); + return fds[slot].fd; +} + +/* + * Called if kernel wants us to create a shortcut + */ +void create_ingress_svc(uint32_t ipaddr, char *atm_addr) +{ + int i, new_socket; + + new_socket = create_shortcut(atm_addr); + if (new_socket < 0) { + printf("mpcd: io.c: create_ingress_svc: create_shortcut failed\n"); + return; + } + + for (i = first_empty; i < OPEN_MAX; i++) { + if (fds[i].fd >= 0) /* slot in use ? */ + continue; + fds[i].fd = new_socket; + fds[i].events = POLLIN | POLLOUT; + break; + } + if (i == OPEN_MAX) { + printf("mpcd: io.c: create_ingress_svc: create_shortcut: no room for new connection\n"); + return; + } + + socket_type[i] = (OUTGOING_SHORTCUT | CONNECTING); + if (i > fds_used) + fds_used = i; + + /* Store the IP address we are creating this shortcut for */ + dprintf("mpcd: io.c: create_ingress_svc: adding ip 0x%x\n", ipaddr); + for(i = 0; i < OPEN_MAX; i++) + if (ingress_shortcuts[i].state == INGRESS_NOT_USED) + break; + + if (i == OPEN_MAX) { + printf("mpcd: io.c: create_ingress_svc: ingress no more entries\n"); + return; + } + + ingress_shortcuts[i].fd = new_socket; + ingress_shortcuts[i].ipaddr = ipaddr; + ingress_shortcuts[i].state = INGRESS_CONNECTING; +} + +/* + * returns < 0 for error, socket for ok + * + */ +static int create_shortcut(char *atm_addr) +{ + int s, flags, retval; + struct sockaddr_atmsvc addr; + + dprintf("mpcd: io.c: create_shortcut() addr = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + atm_addr[0], atm_addr[1], atm_addr[2], atm_addr[3], atm_addr[4]); + memset(&addr, 0, sizeof(addr)); + addr.sas_family = AF_ATMSVC; + memcpy(addr.sas_addr.prv, atm_addr, ATM_ESA_LEN); + s = get_socket(&data_listen_addr); + dprintf("mpcd: create_shortcut() got fd %d \n", s); + if ( (flags = fcntl(s, F_GETFL)) < 0) { + printf("mpcd: io.c: fcntl(F_GETFL) failed: %s\n", strerror(errno)); + close(s); + return -1; + } + if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { + printf("mpcd: io.c: fcntl(F_SETFL) failed: %s\n", strerror(errno)); + close(s); + return -1; + } + retval = connect(s, (struct sockaddr *)&addr, sizeof(addr)); + if (retval < 0 && errno != EINPROGRESS) { + printf("mpcd: io.c: create_shortcut: connect failed: %s\n", strerror(errno)); + return -1; + } + + return s; +} + +/* + * Creates an active connection to MPS + * + * returns < 0 for error + */ +static int connect_to_MPS(){ + + int c; + struct sockaddr_atmsvc mps_ctrl_addr; + struct sockaddr_atmsvc ctrl_listen_addr; + memset(&mps_ctrl_addr,0,sizeof(struct sockaddr_atmsvc)); + memset(&ctrl_listen_addr,0,sizeof(struct sockaddr_atmsvc)); + memcpy(mps_ctrl_addr.sas_addr.prv,MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); + memcpy(ctrl_listen_addr.sas_addr.prv,OWN_ATM_ADDRESS,ATM_ESA_LEN); + mps_ctrl_addr.sas_family = AF_ATMSVC; + ctrl_listen_addr.sas_family = AF_ATMSVC; + MPS_socket = get_socket(&ctrl_listen_addr); + if (MPS_socket < 0) + return -1; + c = connect(MPS_socket, (struct sockaddr *)&(mps_ctrl_addr), + sizeof(struct sockaddr_atmsvc)); + if( c < 0 ){ + printf("mpcd: io.c: connect to MPS failed: %s \n",strerror(errno)); + close(MPS_socket); + return -1; + } + return 0; +} diff -ur --new-file old/atm/mpoad/io.h new/atm/mpoad/io.h --- old/atm/mpoad/io.h Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/io.h Mon Aug 3 14:22:51 1998 @@ -0,0 +1,35 @@ +#ifndef _MPOA_IO_H +#define _MPOA_IO_H +#include + +#define MAX_PACKET_LENGTH 4096 /* max size of MPOA ctrl or data packet */ + +void main_loop(int listen_socket); +int send_to_mps(char *buff, int length); +int send_to_dataplane(char *buff, int length, int fd); +void keep_alive_sm(unsigned keep_alive_lifetime, int sequence_number); +int get_socket(struct sockaddr_atmsvc *address); +void create_ingress_svc(uint32_t ipaddr, char *atm_addr); + +/* Socket types and states */ +#define NOT_USED 0x0000 +#define KERNEL 0x0001 +#define OUTGOING_CTRL 0x0002 +#define INCOMING_CTRL 0x0004 +#define LISTENING_DATA 0x0010 +#define LISTENING_CTRL 0x0020 +#define OUTGOING_SHORTCUT 0x0100 +#define INCOMING_SHORTCUT 0x0200 + +#define CONNECTING 0x1000 /* For outgoing sockets */ +#define CONNECTED 0x2000 /* For outgoing sockets */ + + +/* states for outgoing ingress shortcuts */ +#define INGRESS_NOT_USED 0 +#define INGRESS_REQUEST_SEND 400 +#define INGRESS_CONNECTING 401 +#define INGRESS_CONNECTED 402 + + +#endif /* _MPOA_IO_H */ diff -ur --new-file old/atm/mpoad/k_interf.c new/atm/mpoad/k_interf.c --- old/atm/mpoad/k_interf.c Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/k_interf.c Fri Aug 7 15:04:39 1998 @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include /* for OPEN_MAX */ +#include +#include +#include +#include "k_interf.h" +#include "packets.h" +#include "io.h" +#include "get_vars.h" + +#if 0 +#define dprintf printf +#else +#define dprintf(format,args...) +#endif + +extern int kernel_socket; /* from main.c */ +extern char MPS_CTRL_ATM_ADDR[]; /* from main.c */ +extern int mps_ctrl_addr_set; /* from main.c */ +extern int keep_alive_sm_running; /* from io.c */ +extern int INTERFACE_NUMBER; /* from main.c */ + + +static void snd_mpoa_res_rqst(struct k_message *msg); +static void snd_mpoa_res_rtry(struct k_message *msg); +static void set_mps_ctrl_addr(struct k_message *msg); +static void stop_keep_alive_sm(void); +/* + * returns < 0 for error + * + */ +int send_to_kernel(struct k_message *msg) +{ + if (write(kernel_socket, msg, sizeof(struct k_message)) != + sizeof(struct k_message) ) { + printf("mpcd: k_interf.c: write to kernel failed!\n"); + return -1; + } + return 1; +} + +/* + * returns 0 for error + * + */ + +int msg_from_kernel(int fd) +{ + ssize_t bytes_read; + struct k_message msg; + memset(&msg,0,sizeof(struct k_message)); + bytes_read = read(fd, (void *)&msg, sizeof(msg)); + if (bytes_read < 0) { + printf("mpcd: k_interf.c: read failed from kernel: %s\n", strerror(errno)); + return 0; + } + + if (bytes_read == 0) { + printf("mpcd: k_interf.c:EOF from kernel\n"); + return 0; + } + if (bytes_read != sizeof(msg)) { + printf("mpcd: k_interf.c: msg from kernel wrong size\n"); + return 0; + } + dprintf("mpcd: k_interf.c: message from kernel: "); + switch(msg.type) { + case SND_MPOA_RES_RQST: + dprintf("snd_mpoa_res_rqst.\n"); + snd_mpoa_res_rqst(&msg); + return 1; + break; /* not reached */ + case SND_MPOA_RES_RTRY: + dprintf("snd_mpoa_res_rtry.\n"); + snd_mpoa_res_rtry(&msg); + return 1; + break; /* not reached */ + case SET_MPS_CTRL_ADDR: + dprintf("set_mps_ctrl_addr.\n"); + set_mps_ctrl_addr(&msg); + return 1; + break; /* not reached */ + case STOP_KEEP_ALIVE_SM: + dprintf("stop_keep_alive_sm.\n"); + stop_keep_alive_sm(); + return 1; + break; /* not reached */ + case EGRESS_ENTRY_REMOVED: + dprintf("egress_entry_removed.\n"); + remove_tag(msg.content.eg_info.tag); + return 1; + break; /* not reached */ + case SND_EGRESS_PURGE: + dprintf("snd_egress_purge,cache_id = %u.\n",msg.content.eg_info.cache_id); + send_egress_cache_purge_request(1, /* No reply */ + msg.content.eg_info.mps_ip, + 32, + get_own_ip_addr(INTERFACE_NUMBER), + msg.content.eg_info.cache_id); + return 1; + break; + case DIE: + dprintf(" die.\n"); + exit(0); + break; + case OPEN_INGRESS_SVC: + dprintf(" open_ingress_svc"); + create_ingress_svc(msg.content.in_info.in_dst_ip, + msg.content.in_info.eg_MPC_ATM_addr); + return 1; + break; + default: + dprintf("unknown message %d", msg.type); + return 0; + break; /* not reached */ + } + return 0; /* not reached */ +} + +static void snd_mpoa_res_rqst(struct k_message *msg){ + send_resolution_request(0, + 1, /* Source ip present */ + msg->content.in_info.in_dst_ip, + 0, /* prefix length */ + msg->content.in_info.service_category); + + return; +} + +static void snd_mpoa_res_rtry(struct k_message *msg){ + uint32_t rqst_id = search_by_type(MPOA_RESOLUTION_REQUEST, + msg->content.in_info.in_dst_ip); + send_resolution_request(rqst_id, + 1, + msg->content.in_info.in_dst_ip, + 0, + msg->content.in_info.service_category); + + return; +} + +static void set_mps_ctrl_addr(struct k_message *msg) +{ + char buffer[ATM_ESA_LEN]; + int i; + struct sockaddr_atmsvc mps_ctrl_addr; + char *buff = buffer; + memcpy(mps_ctrl_addr.sas_addr.prv, msg->MPS_ctrl, ATM_ESA_LEN); + mps_ctrl_addr.sas_family = AF_ATMSVC; + if(mps_ctrl_addr_set && !memcmp(msg->MPS_ctrl,MPS_CTRL_ATM_ADDR,ATM_ESA_LEN)) + return; + if(mps_ctrl_addr_set && memcmp(msg->MPS_ctrl,MPS_CTRL_ATM_ADDR,ATM_ESA_LEN)){ + printf("mpcd: k_interf.c: new MPS %s \n",buff); + return; + } + memcpy(MPS_CTRL_ATM_ADDR, msg->MPS_ctrl, ATM_ESA_LEN); + + printf("mpcd: k_interf.c: setting MPS control ATM address to "); + if(atm2text(buff,ATM_ESA_LEN, (struct sockaddr*)&mps_ctrl_addr, T2A_SVC)<0) { + for (i = 0; i < ATM_ESA_LEN; i++) + printf("%02x", MPS_CTRL_ATM_ADDR[i]); + printf("\n"); + } + else + printf("%s\n", buff); + + mps_ctrl_addr_set = 1; + return; +} + +static void stop_keep_alive_sm(){ + keep_alive_sm_running = 0; + return; +} + + diff -ur --new-file old/atm/mpoad/k_interf.h new/atm/mpoad/k_interf.h --- old/atm/mpoad/k_interf.h Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/k_interf.h Thu Jun 18 13:25:49 1998 @@ -0,0 +1,13 @@ +#ifndef K_INTERF_H +#define K_INTERF_H + +int send_to_kernel( struct k_message *msg); +int msg_from_kernel(int fd); + + +#endif /* K_INTERF_H */ + + + + + diff -ur --new-file old/atm/mpoad/main.c new/atm/mpoad/main.c --- old/atm/mpoad/main.c Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/main.c Fri Aug 7 15:17:31 1998 @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "packets.h" +#include "io.h" +#include "k_interf.h" +#include "get_vars.h" + +/* + * Global variables. + */ +int kernel_socket; /* socket for mpoad <--> kernel messages */ +int MPS_socket; /* MPS control socket for outgoing msgs */ +int MPS_listen_socket; /* listen socket for incoming control calls */ +unsigned char MPS_CTRL_ATM_ADDR[ATM_ESA_LEN]; +unsigned char MPS_MAC_ADDRESS[13]; +int mps_ctrl_addr_set = 0; +int mps_mac_addr_set = 0; +unsigned char OWN_ATM_ADDRESS[ATM_ESA_LEN]; /* Our control ATM address */ +struct sockaddr_atmsvc data_listen_addr; +int INTERFACE_NUMBER; /* Interface number, x for lecx */ + +static void create_kernel_socket(int itf); +static int create_listen_socket(struct sockaddr_atmsvc addr); +static int listen_to_MPS( struct sockaddr_atmsvc ctrl_listen_addr ); +static int set_mps_mac_addr(void); +static void usage(const char *progname); + +static void signal_handler(int sgnl){ + struct k_message msg; + memset(&msg,0,sizeof(struct k_message)); + msg.type = CLEAN_UP_AND_EXIT; + send_to_kernel(&msg); + printf("mpcd: main.c: signal_handler()\n"); + return; +} + + +int main(int argc, char **argv){ + int listen_socket; + int opt_ret = 0; + struct k_message msg; + struct sockaddr_atmsvc control_listen_addr; + struct sockaddr_atmsvc mps_ctrl_addr; + memset(&control_listen_addr,0,sizeof(struct sockaddr_atmsvc)); + memset(&data_listen_addr,0,sizeof(struct sockaddr_atmsvc)); + memset(&mps_ctrl_addr,0,sizeof(struct sockaddr_atmsvc)); + memset(&msg,0,sizeof(struct k_message)); + while( opt_ret != -1 ){ + opt_ret = getopt(argc, argv, "h:s:l:c:i:m:"); + switch(opt_ret) { + case 'h': + usage(argv[0]); + exit(0); + break; + case 's': + if(text2atm(optarg,(struct sockaddr *)&control_listen_addr, + sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ + printf("mpcd: main.c: text2atm failed.\n"); + usage(argv[0]); + exit(1); + } + memcpy(OWN_ATM_ADDRESS,control_listen_addr.sas_addr.prv, ATM_ESA_LEN); + break; + case 'l': + if(text2atm(optarg,(struct sockaddr *)&data_listen_addr, + sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ + printf("mpcd: main.c: text2atm failed.\n"); + usage(argv[0]); + exit(1); + } + break; + case 'c': + if(text2atm(optarg,(struct sockaddr *)&mps_ctrl_addr, + sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ + printf("mpcd: main.c: text2atm failed.\n"); + usage(argv[0]); + exit(1); + } + memcpy(MPS_CTRL_ATM_ADDR,mps_ctrl_addr.sas_addr.prv,ATM_ESA_LEN); + mps_ctrl_addr_set = 1; + break; + case 'm': + strncpy(MPS_MAC_ADDRESS,optarg,13); + mps_mac_addr_set = 1; + break; + case 'i': + INTERFACE_NUMBER = atoi(optarg); + break; + } + } + create_kernel_socket(INTERFACE_NUMBER); + msg.type = SET_MPC_CTRL_ADDR; + memcpy(msg.MPS_ctrl,OWN_ATM_ADDRESS,ATM_ESA_LEN); + if (send_to_kernel(&msg) < 0) { + printf("mpcd: main.c: send_to_kernel(SET_MPC_CTRL_ADDR) failed\n"); + exit(1); + } + if(mps_mac_addr_set) + set_mps_mac_addr(); + listen_to_MPS( control_listen_addr ); + if ( (listen_socket = create_listen_socket(data_listen_addr)) < 0) { + printf("mpcd: main.c: listen_socket creation failed\n"); + exit (1); + } + + signal(SIGHUP, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGQUIT, signal_handler); + signal(SIGABRT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGSEGV, signal_handler); + + main_loop(listen_socket); + return 0; +} + +static void create_kernel_socket(int itf) +{ + kernel_socket = socket(PF_ATMSVC, SOCK_DGRAM, 0); + if (kernel_socket < 0) { + printf("mpcd: main.c: kernel socket creation failed: %s\n", strerror(errno)); + exit (1); + } + if ( ioctl(kernel_socket, ATMMPC_CTRL, itf) < 0) { + printf("mpcd: main.c: kernel socket ioctl(ATMMPC_CTRL) failed: %s\n", strerror(errno)); + exit (1); + } + return; +} + +/* + * Listen socket for incoming shortcuts + * + * return < 0 for error, socket for ok + * + */ +static int create_listen_socket(struct sockaddr_atmsvc addr) +{ + int s; + + s = get_socket(&addr); + if (s < 0) + return -1; + + if (listen(s, 5) < 0) { + printf("mpcd: main.c: listen failed: %s\n",strerror(errno)); + close(s); + return -1; + } + + return s; +} + +static int listen_to_MPS( struct sockaddr_atmsvc ctrl_listen_addr ){ + /* soketti, joka kuuntelee MPC:n Control ATM-osoitteessa */ + MPS_listen_socket = create_listen_socket(ctrl_listen_addr); + if (MPS_listen_socket < 0) + return -1; + return 0; +} + +static int set_mps_mac_addr(){ + char *string = MPS_MAC_ADDRESS; + struct k_message msg; + unsigned char mac_addr[ETH_ALEN]; + int tmp; + int i = strlen(string); + memset(&msg,0,sizeof(struct k_message)); + if (i != 12){ + printf("mpcd: main.c: incorrect mac address.\n"); + exit(1); + } + for(i=0;i<6;i++) { + sscanf(&string[i*2],"%2x",&tmp); + mac_addr[i]=(unsigned char)tmp; + } + msg.type = SET_MPS_MAC_ADDR; + memcpy(&msg.MPS_ctrl,&mac_addr,ETH_ALEN); + send_to_kernel(&msg); + return 0; +} + + + +static void usage( const char * progname ){ + printf("Usage: %s [-s our_control_listen_ATM_Address] [-l our_data_listen_address]\n" + " [-c MPS_control_ATM_Address] [-i interface_number]\n" + " [-m MPS_MAC_address]\n", + progname); + return; +} diff -ur --new-file old/atm/mpoad/mpcd.8 new/atm/mpoad/mpcd.8 --- old/atm/mpoad/mpcd.8 Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/mpcd.8 Fri Aug 7 16:02:02 1998 @@ -0,0 +1,51 @@ +.TH mpcd 8 "Jul 29, 1998" "Linux" "Maintenance Commands" +.SH NAME +mpcd \- ATM MPOA (Multi\-Protocol Over ATM) client daemon +.SH SYNOPSIS +.B mpcd +.RB [ \-s\ \fIControl\ ATM\ address\fP ] +.RB [ \-l\ \fIData\ ATM\ address\fP ] +.RB [ \-c\ \fIMPS\ control\ ATM\ address\fP ] +.RB [ \-i\ \fIInterface\ number\fP ] +.RB [ \-m\ \fIMPS\ MAC\ address\fP ] +.SH DESCRIPTION +MPOA client (MPC) is responsible for creating and receiving +internetwork layer shortcuts. Using these shortcuts MPCs forward +unicast internetwork layer packets effectively over ATM without need +for routing protocols. +.PP +MPC has two roles; ingress and egress. In ingress role MPC detects +flows destined outside it's own subnet and tries to establish +shortcuts to those destinations. In egress role MPC accepts shortcuts +and packets arriving on those shortcuts. Maintaining shortcuts is done +with the help of MPOA server (MPS). +.PP +Like Linux LAN Emulation client; MPOA client is also divided in two +parts. The parts are kernel component and an daemon process +\fBmpcd(8)\fP. \fBmpcd(8)\fP opens and receives shortcuts and control +connections with the kernel component. The kernel component tallies +packets flowing in and out and makes the decision if a packet should +be forward using LANE or MPOA shortcuts. +.PP +Linux MPOA client only supports non-LLC-muxed shortcuts. The number of +supported MPOA clients is unlimited. +.SH OPTIONS +.IP \fB\-s\ \fIControl\ ATM\ address\fP +Local ATM address this MPC used for MPOA control connections. +.IP \fB\-l\ \fIData\ ATM\ address\fP +Local ATM address from and to which MPOA shortcuts are established. +.IP \fB\-c\ \fIMPS\ control\ ATM\ address\fP +ATM address of MPS. Only needed if MPS can not advertise it by +itself. +.IP \fB\-i\ \fIInterface\ number\fP +The interface number of LEC this MPC serves. E.g. 2 for "lec2". +.IP \fB\-m\ \fIMPS\ MAC\ address\fP +MAC address of default router where MPS recides. Not needed if MPS can +correctly advertise it via MPOA device discovery. +.SH BUGS +Supports only Ethernet type of ELANs. Probably others too. +.SH AUTHORS +Heikki Vatiainen , Sampo Saaristo +.SH "SEE ALSO" +zeppelin(8), atmsigd(8) +.\"{{{}}} diff -ur --new-file old/atm/mpoad/p_factory.c new/atm/mpoad/p_factory.c --- old/atm/mpoad/p_factory.c Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/p_factory.c Mon Aug 10 14:52:47 1998 @@ -0,0 +1,390 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "packets.h" +#include "get_vars.h" +#include "io.h" + +#if 0 +#define dprintf printf +#else +#define dprintf(format,args...) +#endif + +extern int INTERFACE_NUMBER; /* From main.c */ +extern struct sockaddr_atmsvc data_listen_addr; /* From main.c */ + +/* slightly modified version from RFC 1071 */ +static unsigned short compute_ip_csum(unsigned char *addr, int count) +{ + /* Compute Internet Checksum for "count" bytes + * beginning at location "addr". + */ + uint32_t sum = 0; + + while( count > 1 ) { + /* This is the inner loop */ + sum += * ((uint16_t *) addr)++; + count -= 2; + } + + /* Add left-over byte, if any */ + if( count > 0 ) + sum += * (unsigned char *) addr; + + /* Fold 32-bit sum to 16 bits */ + while (sum>>16) + sum = (sum & 0xffff) + (sum >> 16); + + return (~sum); +} + + +/* + * Prefills the fixed header. + * Only question is wheter the NBMA subaddress + * can really be omitted or not. + */ +static void prefill_fixed_h(struct nhrp_fixed_h *header){ + header->ar_afn = htons(AR_AFN_NSAP); + header->ar_pro_type = htons(AR_PRO_TYPE_ETHER); + header->ar_hopcnt = get_ttl(); /* get_vars.c */ + header->ar_op_version = AR_OP_VERSION_NHRP; + header->ar_shtl = AR_SHTL_NSAP; + header->ar_sstl = 0; +} + +/* + * Prefills the common header. + */ +static void prefill_common_h(struct nhrp_common_h *header){ + header->src_proto_len = PROTO_LEN_IP; + header->dst_proto_len = PROTO_LEN_IP; + get_own_atm_addr(header->src_nbma_address); + header->src_protocol_address = htonl(get_own_ip_addr(INTERFACE_NUMBER)); +} + +/* + * Prefills the common header without the source IP_address + */ +static void prefill_common_h_short(struct nhrp_common_h_short *header){ + header->src_proto_len = 0; + header->dst_proto_len = PROTO_LEN_IP; + get_own_atm_addr(header->src_nbma_address); +} + +/* + * Generates a new request id. + */ +static uint32_t Request_ID(void){ + static uint32_t id = 0; + id = (id + 1) % UINT_MAX; + return id; +} + + +/* + * Fills the checksum and length fields in the fixed header. + */ +static void finish(int length, uint8_t *buff, + struct nhrp_fixed_h *fixed){ + int append = length; + fixed->ar_pktsz = htons(length); + if(append % 2 == 1){ + append++; + } + fixed->ar_chksum = (compute_ip_csum(buff,append)); + return; +} + +/* + * NHRP purge request. + */ +int send_purge_request( + uint32_t src_ip, + uint8_t prefix_length, + uint32_t purge_ip, + int shortcut_fd + ){ + int pos = 0; + struct nhrp_fixed_h *fixed; + struct nhrp_common_h_short *common_short; + struct nhrp_common_h_no_ip *common_no_ip; + struct nhrp_cie_short *cie_short; + uint8_t buffer[MAX_PACKET_LENGTH]; + uint8_t *buff = buffer; + memset(buff,0,MAX_PACKET_LENGTH); + fixed = (struct nhrp_fixed_h *)buff; + prefill_fixed_h(fixed); + fixed->ar_op_type = NHRP_PURGE_REQUEST; + pos += sizeof(struct nhrp_fixed_h); + if(src_ip){ + common_short = (struct nhrp_common_h_short *)(buff + pos); + common_short->src_proto_len = PROTO_LEN_IP; + common_short->dst_proto_len = 0; + get_own_atm_addr(common_short->src_nbma_address); + common_short->flags = htons(common_short->flags | FLAG_N); + common_short->dst_protocol_address = src_ip; + pos += sizeof(struct nhrp_common_h_short); + } + else{ + common_no_ip = (struct nhrp_common_h_no_ip *)(buff + pos); + get_own_atm_addr(common_no_ip->src_nbma_address); + common_no_ip->flags = htons(common_no_ip->flags | FLAG_N); + pos += sizeof(struct nhrp_common_h_no_ip); + } + cie_short = (struct nhrp_cie_short *)(buff + pos); + cie_short->prefix_length = prefix_length; + cie_short->cli_proto_len = PROTO_LEN_IP; + pos += sizeof(struct nhrp_cie_short); + *((uint32_t *)(buff + pos)) = htonl(purge_ip); + pos += sizeof(purge_ip); + finish(pos, buff, fixed); + return send_to_dataplane(buff, pos, shortcut_fd); +} + +/* + * NHRP purge reply. Sent in response to NHRP purge request if N-flag + * is not set. Only the packet type is changed and new checksum calculated. + */ +int send_purge_reply(uint8_t *buff) +{ + int pos; + struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; + fixed->ar_op_type = NHRP_PURGE_REPLY; + pos = ntohs(fixed->ar_pktsz); + finish(pos, buff, fixed); + return send_to_mps(buff, pos); +} + +/* + * MPOA resolution request. + */ +int send_resolution_request(uint32_t rqst_id, + uint16_t source_ip_present, + uint32_t dest_ip, + uint8_t prefix_length, + uint32_t service_category){ + int pos = 0; + struct nhrp_fixed_h *fixed; + struct nhrp_common_h *common; + struct nhrp_common_h_short *common_s; + struct nhrp_extension *extension; + struct nhrp_cie_short *cie; + struct nhrp_extension_with_value *extension_with_value; + uint8_t buff[MAX_PACKET_LENGTH]; + memset(buff,0,MAX_PACKET_LENGTH); + + dprintf("mpcd: p_factory.c: sending a resolution request %x ",dest_ip); + + fixed = (struct nhrp_fixed_h *)buff; + prefill_fixed_h(fixed); + fixed->ar_op_type = MPOA_RESOLUTION_REQUEST; + pos += sizeof(struct nhrp_fixed_h); + if( source_ip_present ){ + common = (struct nhrp_common_h *)(buff + sizeof(struct nhrp_fixed_h)); + prefill_common_h(common); + pos += sizeof(struct nhrp_common_h); + common->dst_protocol_address = dest_ip; + if(!rqst_id){ + common->request_ID = htonl(Request_ID()); + new_id(ntohl(common->request_ID),dest_ip,MPOA_RESOLUTION_REQUEST); + } + else + common->request_ID = htonl(rqst_id); + dprintf("mpcd: p_factory.c: with request_id %d\n",ntohl(common->request_ID)); + } + else{ + common_s = (struct nhrp_common_h_short *)(buff + sizeof(struct nhrp_fixed_h)); + prefill_common_h_short(common_s); + pos += sizeof(struct nhrp_common_h_short); + common_s->dst_protocol_address = dest_ip; + if(!rqst_id){ + common_s->request_ID = htonl(Request_ID()); + new_id(ntohl(common_s->request_ID),dest_ip,MPOA_RESOLUTION_REQUEST); + } + else + common_s->request_ID = htonl(rqst_id); + dprintf("mpcd: p_factory.c: with request_id %d\n",ntohl(common_s->request_ID)); + } + + cie = (struct nhrp_cie_short *)(buff + pos); + cie->prefix_length = MAX_PREFIX_LENGTH; + pos += sizeof(struct nhrp_cie_short); + + fixed->ar_extoff = htons(pos); + extension = (struct nhrp_extension *)(buff + pos); + extension->type = htons(MPOA_EGRESS_CACHE_TAG_EXTENSION); + extension->length = 0; + pos += sizeof(struct nhrp_extension); + if(service_category){ + extension_with_value = (struct nhrp_extension_with_value *)(buff + pos); + extension_with_value->type = htons(MPOA_ATM_SERVICE_CATEGORY_EXTENSION); + extension_with_value->length = htons(sizeof(service_category)); + extension_with_value->value = htonl(service_category); + pos += sizeof(struct nhrp_extension_with_value); + } + extension = (struct nhrp_extension *)(buff + pos); + extension->type = htons(NHRP_END_OF_EXTENSIONS); + extension->length = 0; + pos += sizeof(struct nhrp_extension); + + finish(pos,buff,fixed); + return send_to_mps(buff,pos); +} + +/* + * Sent as a reply to cache impositon request. + */ +int send_cache_imposition_reply( + uint8_t *request, + uint32_t tag, + uint8_t code, + uint8_t prefix_length, + uint16_t mtu, + uint8_t cli_atm_addr[ATM_ESA_LEN] + ){ + int pos = 0; + struct nhrp_fixed_h *fixed; + struct nhrp_fixed_h *fixed_request; + struct nhrp_extension *extension; + struct nhrp_extension_with_value *extension_with_value; + struct dll_header_extension *dll_ext; + struct extension_values values; + struct nhrp_common_h *common; + struct nhrp_cie_no_ip *cie; + struct nhrp_cie_short *cie_short; + uint8_t buffer[MAX_PACKET_LENGTH]; + uint8_t *reply = buffer; + + memset(reply,0,MAX_PACKET_LENGTH); + fixed = (struct nhrp_fixed_h *)reply; + prefill_fixed_h(fixed); + fixed->ar_op_type = MPOA_CACHE_IMPOSITION_REPLY; + pos += sizeof(struct nhrp_fixed_h); + common = (struct nhrp_common_h *) memcpy(reply+pos, + request+pos, + sizeof(struct nhrp_common_h)); + pos += sizeof(struct nhrp_common_h); + if( !code ){ + cie = (struct nhrp_cie_no_ip *)(reply + pos); + cie->code = code; + if(prefix_length) + cie->prefix_length = prefix_length; + else + cie->prefix_length = MAX_PREFIX_LENGTH; + cie->mtu = MTU_DEFAULT; + cie->cli_addr_tl = ATM_ESA_LEN; + cie->cli_saddr_tl = 0; + cie->cli_proto_len = 0; + memcpy(cie->cli_nbma_address,data_listen_addr.sas_addr.prv,ATM_ESA_LEN); + pos += sizeof(struct nhrp_cie_no_ip); + } + else{ + cie_short = (struct nhrp_cie_short *)(reply + pos); + cie_short->code = code; + cie_short->prefix_length = prefix_length; + cie_short->mtu = mtu; + pos += sizeof(struct nhrp_cie_short); + } + fixed_request = (struct nhrp_fixed_h *)request; + + parse_extensions(request+ntohs(fixed_request->ar_extoff),&values); + fixed->ar_extoff = htons(pos); + extension_with_value = (struct nhrp_extension_with_value *)(reply + pos); + extension_with_value->type = htons(MPOA_EGRESS_CACHE_TAG_EXTENSION); + extension_with_value->length = htons(sizeof(tag)); + extension_with_value->value = tag; + pos += sizeof(struct nhrp_extension_with_value); + if(values.service_category_present){ + extension_with_value = (struct nhrp_extension_with_value *)(reply + pos); + extension_with_value->type = htons(MPOA_ATM_SERVICE_CATEGORY_EXTENSION); + extension_with_value->length = htons(sizeof(values.service_category)); + extension_with_value->value = htonl(values.service_category); + pos += sizeof(struct nhrp_extension_with_value); + } + if(values.dll_header_present){ + dll_ext = (struct dll_header_extension *)(reply + pos); + dll_ext->type = htons(MPOA_DLL_HEADER_EXTENSION); + dll_ext->length = values.dll_ext.length; + dll_ext->cache_id = values.dll_ext.cache_id; + dll_ext->elan_id = values.dll_ext.elan_id; + dll_ext->dh_length = values.dll_ext.dh_length; + memcpy(dll_ext->dll_header,values.dll_ext.dll_header,values.dll_ext.dh_length); + pos += 13 + 14; + } + extension = (struct nhrp_extension *)(reply + pos); + extension->type = htons(NHRP_END_OF_EXTENSIONS); + extension->length = 0; + pos += sizeof(struct nhrp_extension); + finish(pos, reply, fixed); + return send_to_mps(reply,pos); +} + + +int send_egress_cache_purge_request( + uint16_t no_reply, + uint32_t eg_MPS_ip_addr, + uint8_t prefix, + uint32_t purge_ip, + uint32_t cache_id + ) +{ + int pos = 0; + struct nhrp_fixed_h *fixed; + struct dll_header_extension *extension_dll; + struct nhrp_extension *extension; + struct nhrp_common_h *common; + struct nhrp_cie *cie; + uint8_t buffer[MAX_PACKET_LENGTH]; + uint8_t *buff = buffer; + + memset(buff,0,MAX_PACKET_LENGTH); + fixed = (struct nhrp_fixed_h *)buff; + prefill_fixed_h(fixed); + fixed->ar_op_type = MPOA_EGRESS_CACHE_PURGE_REQUEST; + pos += sizeof(struct nhrp_fixed_h); + common = (struct nhrp_common_h *)(buff + pos); + if(no_reply) + common->flags = htons(common->flags | FLAG_N); + common->request_ID = htonl(Request_ID()); + new_id(ntohl(common->request_ID),cache_id,MPOA_EGRESS_CACHE_PURGE_REQUEST); + prefill_common_h(common); + common->dst_protocol_address = ntohl(eg_MPS_ip_addr); + pos += sizeof(struct nhrp_common_h); + cie = (struct nhrp_cie *)(buff + pos); + cie->prefix_length = prefix; + cie->cli_addr_tl = ATM_ESA_LEN; + cie->cli_proto_len = PROTO_LEN_IP; + cie->cli_protocol_address = htonl(purge_ip); + get_own_atm_addr(cie->cli_nbma_address); + pos += sizeof(struct nhrp_cie); + fixed->ar_extoff = htons(pos); + extension_dll = (struct dll_header_extension *)(buff + pos); + extension_dll->type = htons(MPOA_DLL_HEADER_EXTENSION); + extension_dll->length = htons(9); /* FIXME: needs at least checking */ + extension_dll->cache_id = cache_id; + dprintf("mpcd: p_factory.c: egress cache_purge_request, cache_id = %u",cache_id); + pos += 13; + extension = (struct nhrp_extension *)(buff + pos); + extension->type = htons(NHRP_END_OF_EXTENSIONS); + pos += sizeof(struct nhrp_extension); + finish(pos, buff, fixed); + return send_to_mps(buff,pos); +} + +int send_egress_cache_purge_reply(uint8_t *buff){ + int pos; + struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; + fixed->ar_op_type = MPOA_EGRESS_CACHE_PURGE_REPLY; + pos = ntohs(fixed->ar_pktsz); + finish(pos, buff, fixed); + return send_to_mps(buff,pos); +} diff -ur --new-file old/atm/mpoad/p_recogn.c new/atm/mpoad/p_recogn.c --- old/atm/mpoad/p_recogn.c Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/p_recogn.c Fri Aug 7 15:17:04 1998 @@ -0,0 +1,361 @@ +#include +#include +#include +#include +#include +#include +#include +#include "io.h" +#include "k_interf.h" +#include "packets.h" + +extern uint8_t MPS_CTRL_ATM_ADDR[]; /* from main.c */ +extern int keep_alive_sm_running; /* from io.c */ + +#if 0 +#define dprintf printf +#else +#define dprintf(format,args...) +#endif + +int parse_extensions(uint8_t *buff,struct extension_values * values ){ + int pos = 0; + struct dll_header_extension *dll_ext; + struct nhrp_extension_with_value *ext_with_value; + struct nhrp_extension *extension = (struct nhrp_extension *)buff; + + memset(values, 0, sizeof(struct extension_values)); + while(ntohs(extension->type) != NHRP_END_OF_EXTENSIONS && + ntohs(extension->type) != 0){ + switch(ntohs(extension->type)){ + case MPOA_DLL_HEADER_EXTENSION: + dprintf("mpcd: p_recogn.c: dll_header_extension.\n"); + dll_ext = (struct dll_header_extension *)(buff + pos); + values->dll_header_present = 1; + values->dll_ext.length = dll_ext->length; + values->dll_ext.cache_id = dll_ext->cache_id; + dprintf("mpcd: p_recogn.c: parse_extentsions() cache_id %d\n", dll_ext->cache_id); + values->dll_ext.elan_id = dll_ext->elan_id; + values->dll_ext.dh_length = dll_ext->dh_length; + memcpy(values->dll_ext.dll_header,dll_ext->dll_header + ,dll_ext->dh_length); + pos += sizeof(struct dll_header_extension) - + sizeof(dll_ext->dll_header) + dll_ext->dh_length; + dprintf("mpcd: p_recogn.c: parse_extensions() pos %d values->dll_ext.cache_id %d\n", pos, values->dll_ext.cache_id); + break; + case MPOA_EGRESS_CACHE_TAG_EXTENSION: + dprintf("mpcd: p_recogn.c: mpoa_egress_cache_tag_extension.\n"); + extension = (struct nhrp_extension *)(buff + pos); + if(ntohs(extension->length)){ + values->tag_present = 1; + pos += sizeof(struct nhrp_extension); + values->tag = *((uint32_t*)(buff + pos)); + pos += sizeof(uint32_t); + } + else + pos += sizeof(struct nhrp_extension_with_value); + break; + case MPOA_ATM_SERVICE_CATEGORY_EXTENSION: + dprintf("mpcd: p_recogn.c: mpoa_atm_service_category_extension.\n"); + ext_with_value = (struct nhrp_extension_with_value *)(buff + pos); + values->service_category_present = 1; + values->service_category = ntohl(ext_with_value->value); + pos += sizeof(struct nhrp_extension_with_value); + break; + case MPOA_KEEPALIVE_LIFETIME_EXTENSION: + dprintf("mpcd: p_recogn.c: mpoa_keepalive_lifetime_extension.\n"); + ext_with_value = (struct nhrp_extension_with_value *)(buff + pos); + values->keep_alive_lifetime_present = 1; + values->keep_alive_lifetime = ntohl(ext_with_value->value); + pos += sizeof(struct nhrp_extension_with_value); + break; + case MPOA_HOP_COUNT_EXTENSION: + dprintf("mpcd: p_recogn.c: mpoa_hop_count_extension.\n"); + ext_with_value = (struct nhrp_extension_with_value *)(buff + pos); + values->hop_count_present = 1; + values->hop_count = ntohl(ext_with_value->value); + pos += sizeof(struct nhrp_extension_with_value); + break; + case MPOA_ORIGINAL_ERROR_CODE_EXTENSION: + dprintf("mpcd: p_recogn.c: mpoa_original_error_code_extension.\n"); + ext_with_value = (struct nhrp_extension_with_value *)(buff + pos); + values->error_code_present = 1; + values->error_code = ntohl(ext_with_value->value); + pos += sizeof(struct nhrp_extension_with_value); + break; + default: + printf("mpcd: p_recogn.c: Unrecognized extension: %x\n",ntohs(extension->type)); + pos += sizeof(struct nhrp_extension_with_value); + break; + } + extension = (struct nhrp_extension *)(buff + pos); + } + if(pos) + pos += sizeof(struct nhrp_extension); /* End_of_extensions extension */ + return pos; +} + +static void print_cie_code(uint8_t code){ + printf("mpcd: p_recogn.c: resolution_reply_rcvd: "); + switch(code){ + case ADMINISTRATIVELY_PROHIBITED: + printf("administratively prohibited. \n"); + break; + case INSUFFICIENT_RESOURCES: + printf("insufficient resources. \n"); + break; + case NO_INET_ADDR_TO_NBMA_ADDR_BINDING_EXISTS: + printf("no internet layer address to nbma address binding exists.\n"); + break; + case UNIQUE_INET_ADDR_ALREADY_REGISTERED: + printf("unique internet layer address already registered.\n"); + break; + case INSUFF_RES_TO_EGRESS_CACHE_ENTRTY: + printf("insufficient resources to accept egress cache entry.\n"); + break; + case INSUFF_RES_TO_SHORTCUT: + printf("insufficient resources to accpet shortcut.\n"); + break; + case INSUFF_RES_TO_EITHER_ENTRY_OR_SHORTCUT: + printf("insufficient resources to accept either shortcut or egress cache entry.\n"); + break; + case UNSUPPORTED_INTERN_LAYER_PROTO: + printf("unsupported internetwork layer protocol.\n"); + break; + case UNSUPPORTED_MAC_LAYER_PROTO: + printf("unsupported mac layer protocol.\n"); + break; + case NOT_AN_MPC: + printf("not an mpc.\n"); + break; + case NOT_AN_MPS: + printf("not an mps.\n"); + break; + case UNSPECIFIED: + printf("unspecified.\n"); + break; + default: + printf("unrecognized cie code %d.\n",code); + break; + } + return; +} + +static int nhrp_purge_request(uint8_t *buff){ + int pos = 0; + int cie_limit = 0; + uint8_t eg_MPC_data_ATM_addr[ATM_ESA_LEN]; + uint32_t eg_MPS_ip_addr; + uint32_t purge_ip; + struct k_message msg; + struct extension_values values; + struct nhrp_common_h_no_ip *common_no_ip; + struct nhrp_cie_no_nbma *cie_no_nbma; + struct nhrp_cie *cie; + struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; + memset(&msg,0,sizeof(struct k_message)); + if(ntohs(fixed->ar_extoff)){ + cie_limit = ntohs(fixed->ar_extoff); + } + else{ + cie_limit = ntohs(fixed->ar_pktsz); + } + pos += sizeof(struct nhrp_fixed_h); + common_no_ip = (struct nhrp_common_h_no_ip *)(buff + pos); + memcpy(eg_MPC_data_ATM_addr, common_no_ip->src_nbma_address + ,ATM_ESA_LEN); + pos += sizeof(struct nhrp_common_h_no_ip); + if(common_no_ip->src_proto_len == PROTO_LEN_IP){ + eg_MPS_ip_addr = ntohl((uint32_t)*(buff + pos)); + pos += sizeof(eg_MPS_ip_addr); + } + if(common_no_ip->dst_proto_len == PROTO_LEN_IP) + pos += sizeof(uint32_t); + + while(pos < cie_limit){ + cie = (struct nhrp_cie *)(buff + pos); + if(cie->cli_addr_tl){ + purge_ip = cie->cli_protocol_address; + pos += sizeof(struct nhrp_cie); + } + else{ + cie_no_nbma = (struct nhrp_cie_no_nbma *)(buff + pos); + purge_ip = cie_no_nbma->cli_protocol_address; + pos += sizeof(struct nhrp_cie_no_nbma); + } + msg.type = INGRESS_PURGE_RCVD; + msg.content.in_info.in_dst_ip = purge_ip; + memcpy(msg.MPS_ctrl, MPS_CTRL_ATM_ADDR, ATM_ESA_LEN); + send_to_kernel(&msg); + } + if(ntohs(fixed->ar_extoff)){ + pos += parse_extensions(buff + ntohs(fixed->ar_extoff), &values); + } + if(!(ntohs(common_no_ip->flags) & FLAG_N )) + return send_purge_reply(buff); + return 1; +} + +static int mpoa_cache_imposition_request( uint8_t * buff ){ + int pos = 0; + struct k_message msg; + struct nhrp_fixed_h * fixed = (struct nhrp_fixed_h *)buff; + struct nhrp_common_h * common; + struct nhrp_cie_short * cie_short; + struct extension_values values; + pos += sizeof( struct nhrp_fixed_h ); + memset(&msg,0,sizeof(struct k_message)); + common = (struct nhrp_common_h *)(buff + pos); + memcpy(msg.content.eg_info.in_MPC_data_ATM_addr, + common->src_nbma_address ,ATM_ESA_LEN); + pos += sizeof(struct nhrp_common_h); + cie_short = (struct nhrp_cie_short *)(buff + pos); + msg.content.eg_info.holding_time = ntohs(cie_short->holding_time); + if(ntohs(cie_short->holding_time)) + keep_alive_sm_running = 1; + if(ntohs(fixed->ar_extoff)){ + pos += parse_extensions(buff + ntohs(fixed->ar_extoff), &values); + } + msg.content.eg_info.cache_id = values.dll_ext.cache_id; + msg.content.eg_info.DH_length = values.dll_ext.dh_length; + memcpy(msg.content.eg_info.DLL_header, values.dll_ext.dll_header, msg.content.eg_info.DH_length); + if(common->src_proto_len) + msg.content.eg_info.mps_ip = common->src_protocol_address; + if(common->dst_proto_len) + msg.content.eg_info.eg_dst_ip = common->dst_protocol_address; + msg.content.eg_info.tag = new_tag(msg.content.eg_info.cache_id); + memcpy(msg.MPS_ctrl, MPS_CTRL_ATM_ADDR, ATM_ESA_LEN); + msg.type = CACHE_IMPOS_RCVD; + send_to_kernel(&msg); + return send_cache_imposition_reply( buff, msg.content.eg_info.tag, + 0x00, 0, MTU_DEFAULT, + common->src_nbma_address ); +} + +static int mpoa_egress_cache_purge_reply( uint8_t * buff ){ + int pos = 0; + struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; + struct nhrp_common_h *common; + struct extension_values values; + struct k_message msg; + memset(&msg,0,sizeof(struct k_message)); + pos += sizeof(struct nhrp_fixed_h); + common = (struct nhrp_common_h*)(buff + pos); + if(!check_incoming(ntohl(common->request_ID), MPOA_EGRESS_CACHE_PURGE_REQUEST)) + return -1; + if(fixed->ar_extoff) + parse_extensions(buff + ntohs(fixed->ar_extoff),&values); + msg.content.eg_info.cache_id = values.dll_ext.cache_id; + msg.type = EGRESS_PURGE_RCVD; + memcpy(msg.MPS_ctrl,MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); + return send_to_kernel(&msg); +} + +static int mpoa_keep_alive(uint8_t *buff){ + int pos = 0; + uint32_t sequence_nmbr; + struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; + struct extension_values values; + struct nhrp_common_h_no_ip *common; + pos += sizeof(struct nhrp_fixed_h); + common = (struct nhrp_common_h_no_ip *)(buff + pos); + sequence_nmbr = ntohl(common->request_ID); + if(memcmp(common->src_nbma_address,MPS_CTRL_ATM_ADDR,ATM_ESA_LEN)){ + printf("mpcd: p_recogn.c: new MPS! \n" ); + return -1; + } + if(ntohs(fixed->ar_extoff)){ + parse_extensions(buff + ntohs(fixed->ar_extoff),&values); + } + keep_alive_sm(values.keep_alive_lifetime, sequence_nmbr); + return 1; +} + +static int mpoa_trigger( uint8_t * buff ){ + int pos = 0; + struct k_message msg; + struct nhrp_common_h *common; + struct extension_values values; + struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h*)buff; + pos += sizeof(struct nhrp_fixed_h); + common = (struct nhrp_common_h *)(buff + pos); + pos += sizeof(struct nhrp_common_h); + memset(&msg,0,sizeof(struct k_message)); + if(ntohs(fixed->ar_extoff)) + parse_extensions(buff+ntohs(fixed->ar_extoff),&values); + msg.content.in_info.in_dst_ip = common->dst_protocol_address; + memcpy(msg.MPS_ctrl,MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); + msg.type = MPOA_TRIGGER_RCVD; + send_to_kernel(&msg); + return 1; +} + + + +static int mpoa_resolution_reply( uint8_t * buff ){ + int pos = 0; + struct k_message msg; + struct extension_values values; + struct nhrp_common_h *common; + struct nhrp_cie *cie; + struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h*)buff; + memset(&msg,0,sizeof(struct k_message)); + pos += sizeof(struct nhrp_fixed_h); + common = (struct nhrp_common_h*)(buff + pos); + if(!check_incoming(ntohl(common->request_ID),MPOA_RESOLUTION_REQUEST)) + return -1; + pos += sizeof(struct nhrp_common_h); + cie = (struct nhrp_cie*)(buff + pos); + if(cie->code){ + print_cie_code(cie->code); + return -1; + } + msg.content.in_info.holding_time = ntohs(cie->holding_time); + if(fixed->ar_extoff) + pos += parse_extensions(buff + ntohs(fixed->ar_extoff), &values); + if(values.tag_present){ + msg.content.in_info.tag = values.tag; + } + msg.type = MPOA_RES_REPLY_RCVD; + msg.content.in_info.in_dst_ip = common->dst_protocol_address; + memcpy(msg.content.in_info.eg_MPC_ATM_addr,cie->cli_nbma_address,ATM_ESA_LEN); + memcpy(msg.MPS_ctrl,MPS_CTRL_ATM_ADDR, ATM_ESA_LEN); + send_to_kernel(&msg); + keep_alive_sm_running = 1; + return MPOA_RESOLUTION_REPLY; +} + +int recognize_packet(uint8_t * buff){ + struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; + uint8_t type = fixed->ar_op_type; + dprintf("mpcd: p_recogn.c: "); + switch(type){ + case NHRP_PURGE_REQUEST : + dprintf("purge request received.\n"); + return nhrp_purge_request(buff); + case MPOA_CACHE_IMPOSITION_REQUEST : + dprintf("cache imposition request recieved.\n"); + return mpoa_cache_imposition_request(buff); + case MPOA_EGRESS_CACHE_PURGE_REPLY : + dprintf("mpoa egress cache purge reply recieved.\n"); + return mpoa_egress_cache_purge_reply(buff); + case MPOA_KEEP_ALIVE : + dprintf("keep alive recieved. \n"); + return mpoa_keep_alive(buff); + case MPOA_TRIGGER : + dprintf("mpoa trigger recieved. \n"); + return mpoa_trigger(buff); + case MPOA_RESOLUTION_REPLY: + dprintf("mpoa resolution reply recieved. \n"); + return mpoa_resolution_reply(buff); + default: + printf("p_recogn.c: unrecognized packet: %d\n",type); + return -1; + } +} + + + + + + diff -ur --new-file old/atm/mpoad/packets.h new/atm/mpoad/packets.h --- old/atm/mpoad/packets.h Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/packets.h Mon Aug 3 13:41:21 1998 @@ -0,0 +1,355 @@ +#include +#include +#ifndef PACKETS_H +#define PACKETS_H + +/* p_factory.c */ + +int send_resolution_request( + uint32_t rqst_id, + uint16_t source_ip_present, + uint32_t dest_ip, + uint8_t prefix_length, + uint32_t service_category + ); + +int send_cache_imposition_reply( + uint8_t * pRequest, + uint32_t tag, + uint8_t code, + uint8_t prefix_length, + uint16_t mtu, + uint8_t * cli_atm_addr + ); + +int send_egress_cache_purge_request( + uint16_t no_reply, + uint32_t eg_MPS_ip_addr, + uint8_t prefix, + uint32_t purge_ip, + uint32_t cache_id + ); + +int send_purge_request( + uint32_t src_ip, + uint8_t prefix_length, + uint32_t purge_ip, + int shortcut_fd + ); + +int send_purge_reply( + uint8_t * pBuff + ); + +/* p_recogn.c */ + +/* + * Struct is filled by parse_extensions(). + */ + +int recognize_packet( + uint8_t * pBuff + ); + +/* id_list.c */ + +int new_id( + uint32_t id, + uint32_t cache_id, + uint8_t type + ); + +uint32_t search_by_type( + uint8_t type, + uint32_t cache_id + ); + +void clear_expired(void); + +int check_incoming( + uint32_t id, + uint8_t type + ); + +/* tag_list.c */ + +uint32_t new_tag(uint32_t cache_id); + +int remove_tag(uint32_t tag); + +/* NHRP fixed header */ + +struct nhrp_fixed_h { + uint16_t ar_afn; + uint16_t ar_pro_type; + uint8_t ar_pro_snap[5]; /* == 0 */ + uint8_t ar_hopcnt; + uint16_t ar_pktsz; + uint16_t ar_chksum; + uint16_t ar_extoff; + uint8_t ar_op_version; /* 0x01 (NHRP) */ + uint8_t ar_op_type; + uint8_t ar_shtl; + uint8_t ar_sstl; /* == 0 no subaddress concept */ +}; + +/* NHRP common header */ + +struct nhrp_common_h { + uint8_t src_proto_len; + uint8_t dst_proto_len; + uint16_t flags; + uint32_t request_ID; + uint8_t src_nbma_address[ATM_ESA_LEN]; + uint32_t src_protocol_address; /* IP-address */ + uint32_t dst_protocol_address; +}; + +/* NHRP common header without source (or dest.) IP-address */ + +struct nhrp_common_h_short { + uint8_t src_proto_len; + uint8_t dst_proto_len; + uint16_t flags; + uint32_t request_ID; + uint8_t src_nbma_address[ATM_ESA_LEN]; + uint32_t dst_protocol_address; +}; + +/* NHRP common header without source or dest IP-addresses */ + +struct nhrp_common_h_no_ip { + uint8_t src_proto_len; + uint8_t dst_proto_len; + uint16_t flags; + uint32_t request_ID; + uint8_t src_nbma_address[ATM_ESA_LEN]; +}; + + +/* NHRP CIE */ + +struct nhrp_cie { + uint8_t code; + uint8_t prefix_length; + uint16_t unused; + uint16_t mtu; + uint16_t holding_time; + uint8_t cli_addr_tl; + uint8_t cli_saddr_tl; + uint8_t cli_proto_len; + uint8_t preference; + uint8_t cli_nbma_address[ATM_ESA_LEN]; + uint32_t cli_protocol_address; +}; + +/* NHRP CIE without IP-address */ +struct nhrp_cie_no_ip { + uint8_t code; + uint8_t prefix_length; + uint16_t unused; + uint16_t mtu; + uint16_t holding_time; + uint8_t cli_addr_tl; + uint8_t cli_saddr_tl; + uint8_t cli_proto_len; + uint8_t preference; + uint8_t cli_nbma_address[ATM_ESA_LEN]; +}; + +/* NHRP CIE without NBMA addresses */ + +struct nhrp_cie_no_nbma { + uint8_t code; + uint8_t prefix_length; + uint16_t unused; + uint16_t mtu; + uint16_t holding_time; + uint8_t cli_addr_tl; + uint8_t cli_saddr_tl; + uint8_t cli_proto_len; + uint8_t preference; + uint32_t cli_protocol_address; +}; + +/* NHRP CIE without any addresses */ +struct nhrp_cie_short { + uint8_t code; + uint8_t prefix_length; + uint16_t unused; + uint16_t mtu; + uint16_t holding_time; + uint8_t cli_addr_tl; + uint8_t cli_saddr_tl; + uint8_t cli_proto_len; + uint8_t preference; +}; + + +/* NHRP error indication */ + +struct nhrp_error_indication { + uint8_t src_proto_len; + uint8_t dst_proto_len; + uint16_t unused; + uint16_t error_code; + uint16_t error_offset; + uint8_t src_nbma_address[ATM_ESA_LEN]; + uint32_t src_protocol_address; + uint32_t dst_protocol_address; +}; + +/* NHRP extension */ + +struct nhrp_extension { + uint16_t type; /* includes C and u bits */ + uint16_t length; +}; + + +struct nhrp_extension_with_value { + uint16_t type; + uint16_t length; + uint32_t value; +}; + +struct dll_header_extension { + uint16_t type; + uint16_t length; + uint32_t cache_id; + uint32_t elan_id; + uint8_t dh_length; + uint8_t dll_header[256]; +} __attribute__ ((packed)); /* without ((packed)) sizeof() was 273 */ + +struct extension_values{ + uint32_t dll_header_present; + struct dll_header_extension dll_ext; + uint32_t tag_present; + uint32_t tag; + uint32_t service_category_present; + uint32_t service_category; + uint32_t keep_alive_lifetime_present; + uint32_t keep_alive_lifetime; + uint32_t hop_count_present; + uint32_t hop_count; + uint32_t error_code_present; + uint32_t error_code; +}; + +int parse_extensions(uint8_t *buff, struct extension_values *values); + + +/* Constants for fixed header */ + +#define AR_AFN_NSAP 3 +#define AR_AFN_E164 8 +#define AR_OP_VERSION_NHRP 1 +#define AR_SHTL_NSAP 0x14 +#define AR_PRO_TYPE_ETHER 0x0800 +#define AR_PRO_SNAP_ETHER 0 + +/* Constants for common header */ + +#define PROTO_LEN_IP 4 + +/* Default values */ + +#define MTU_DEFAULT 56325 +#define MAX_PREFIX_LENGTH 0x20 + +/* Extension type codes */ + +#define NHRP_END_OF_EXTENSIONS 0x8000 /* C == 1 */ +#define NHRP_RESPONDER_ADDRESS_EXTENSION 0x8003 +#define NHRP_FWD_TRANSIT_NHS_REC_EXTENSION 0x8004 +#define NHRP_REV_TRANSIT_NHS_REC_EXTENSION 0x8005 +#define NHRP_AUTHENTICATION_EXTENSION 0x8007 +#define NHRP_VENDORPRIVATE_EXTENSION 0x8008 + +#define MPOA_DLL_HEADER_EXTENSION 0x9000 +#define MPOA_EGRESS_CACHE_TAG_EXTENSION 0x1001 /* C == 0 */ +#define MPOA_ATM_SERVICE_CATEGORY_EXTENSION 0x1002 +#define MPOA_KEEPALIVE_LIFETIME_EXTENSION 0x1003 +#define MPOA_HOP_COUNT_EXTENSION 0x1004 +#define MPOA_ORIGINAL_ERROR_CODE_EXTENSION 0x1005 + +/* Type codes (ar$op.type) */ + +#define NHRP_RESOLUTION_REQUEST 0x01 +#define NHRP_RESOLUTION_REPLY 0x02 +#define NHRP_REGISTRATION_REQUEST 0x03 +#define NHRP_REGISTRATION_REPLY 0x04 +#define NHRP_PURGE_REQUEST 0x05 +#define NHRP_PURGE_REPLY 0x06 +#define NHRP_ERROR_INDICATION 0x07 + +#define MPOA_CACHE_IMPOSITION_REQUEST 0x80 +#define MPOA_CACHE_IMPOSITION_REPLY 0x81 +#define MPOA_EGRESS_CACHE_PURGE_REQUEST 0x82 +#define MPOA_EGRESS_CACHE_PURGE_REPLY 0x83 +#define MPOA_KEEP_ALIVE 0x84 +#define MPOA_TRIGGER 0x85 +#define MPOA_RESOLUTION_REQUEST 0x86 +#define MPOA_RESOLUTION_REPLY 0x87 + + +/* Error codes. Used in the "Error Code"-field of an +Error Indication packet. */ + +#define UNRECOGNIZED_EXTENSION 0x0001 +#define NHRP_LOOP_DETECTED 0x0003 +#define PROTOCOL_ADDRESS_UNREACHABLE 0x0006 +#define PROTOCOL_ERROR 0x0007 +#define NHRP_SDU_SIZE_EXCEEDED 0x0008 +#define INVALID_EXTENSION 0x0009 +#define INVALID_RESOLUTION_REPL_RCVD 0x000a +#define AUTHENTICATION_FAILURE 0x000b +#define HOP_COUNT_EXCEEDED 0x000f + +/* NHRP CIE codes */ + +#define ADMINISTRATIVELY_PROHIBITED 0x04 +#define INSUFFICIENT_RESOURCES 0x05 +#define NO_INET_ADDR_TO_NBMA_ADDR_BINDING_EXISTS 0x0c +#define UNIQUE_INET_ADDR_ALREADY_REGISTERED 0x0e + + + +/* MPOA CIE codes */ + +#define SUCCESS 0x00 +#define INSUFF_RES_TO_EGRESS_CACHE_ENTRTY 0x81 +#define INSUFF_RES_TO_SHORTCUT 0x82 +#define INSUFF_RES_TO_EITHER_ENTRY_OR_SHORTCUT 0x83 +#define UNSUPPORTED_INTERN_LAYER_PROTO 0x84 +#define UNSUPPORTED_MAC_LAYER_PROTO 0x85 +#define NOT_AN_MPC 0x86 +#define NOT_AN_MPS 0x87 +#define UNSPECIFIED 0x88 + + +/* FLAGS. The meaning of the flags differ with the type of the packet. */ + +#define FLAG_Q 0x8000 +#define FLAG_A 0x4000 +#define FLAG_D 0x2000 + +#define FLAG_U 0x1000 +#define FLAG_S 0x0800 +#define FLAG_N 0x8000 + +/* Lifetime of struct id's in the id_list */ + +#define ID_EXPIRING_TIME 600 + + +#endif /* PACKETS_H */ + + + + + + + + diff -ur --new-file old/atm/mpoad/tag_list.c new/atm/mpoad/tag_list.c --- old/atm/mpoad/tag_list.c Thu Jan 1 01:00:00 1970 +++ new/atm/mpoad/tag_list.c Fri Aug 7 15:10:09 1998 @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include "packets.h" + +/* Extern func's prototypes found from packets.h */ + +struct tag{ + struct tag *next; + struct tag *prev; + uint32_t tag; + uint32_t cache_id; +}; + +static struct tag *tags = NULL; + +static struct tag *search_tag(uint32_t tag){ + struct tag *ptag = tags; + while(ptag != NULL){ + if(tag == ptag->tag) + return ptag; + ptag = ptag->next; + } + return NULL; +} + +static struct tag *search_id(uint32_t cache_id){ + struct tag *ptag = tags; + while(ptag != NULL){ + if(cache_id == ptag->cache_id) + return ptag; + ptag = ptag->next; + } + return NULL; +} + +static uint32_t get_tag(void){ + static uint32_t tag = 0; + tag = (tag + 1) % UINT_MAX; + return tag; +} + +uint32_t new_tag(uint32_t cache_id){ + struct tag *new; + new = search_id(cache_id); + if(new != NULL) + return new->tag; + new = malloc(sizeof(struct tag)); + memset(new,0,sizeof(struct tag)); + new->tag = get_tag(); + while(search_tag(new->tag) != NULL) + new->tag = get_tag(); + new->next = tags; + if(tags != NULL) + tags->prev = new; + tags = new; + new->cache_id = cache_id; + return new->tag; +} + +int remove_tag(uint32_t tag){ + struct tag *ptag = search_tag(tag); + if(ptag == NULL) + return 0; + printf("mpcd: tag_list.c: removing tag %u from the tag_list.\n",tag); + if(ptag->prev != NULL) + ptag->prev->next = ptag->next; + else + tags = ptag->next; + if(ptag->next != NULL) + ptag->next->prev = ptag->prev; + free(ptag); + return 1; +} + + diff -ur --new-file old/atm/switch/Makefile new/atm/switch/Makefile --- old/atm/switch/Makefile Tue Aug 4 20:00:38 1998 +++ new/atm/switch/Makefile Wed Aug 12 20:35:01 1998 @@ -1,6 +1,8 @@ SW_OBJS=dispatch.o proto.o relay.o route.o sig.o lex.yy.o y.tab.o SUBDIRS=debug tcp +all: + do_all: libsw.a include ../Rules.make diff -ur --new-file old/atm/switch/fab.h new/atm/switch/fab.h --- old/atm/switch/fab.h Tue Aug 4 19:50:46 1998 +++ new/atm/switch/fab.h Wed Aug 12 12:09:26 1998 @@ -30,10 +30,10 @@ /* --- Provided by fabric control ------------------------------------------ */ /* - * Initialize the fabric interface. port_notify is invoked whenever a port - * is added to or removed from the switch. fab_start may invoke port_notify - * before returning. port_notify(X,0) is not invoked until all fab_ops on - * that port have completed. + * Initialize the fabric interface. The fabric control invokes port_notify + * whenever a port is added to or removed from the switch. fab_start may + * invoke port_notify before returning. port_notify(X,0) most not be invoked + * until all fab_ops on that port have completed. */ void fab_start(void (*port_notify)(int number,int up)); diff -ur --new-file old/atm/switch/route.c new/atm/switch/route.c --- old/atm/switch/route.c Thu Apr 16 10:33:48 1998 +++ new/atm/switch/route.c Wed Aug 12 12:32:12 1998 @@ -24,8 +24,7 @@ static ROUTE *routes = NULL; -void put_route(struct sockaddr_atmsvc *addr,int addr_mask, - SIGNALING_ENTITY *sig) +void put_route(struct sockaddr_atmsvc *addr,int addr_mask,SIGNALING_ENTITY *sig) { ROUTE *route; @@ -44,7 +43,18 @@ } -SIGNALING_ENTITY *find_route(struct sockaddr_atmsvc *from, +void get_routes(SIGNALING_ENTITY *sig, + void (*callback)(struct sockaddr_atmsvc *addr,int addr_mask,void *user), + void *user) +{ + ROUTE *route; + + for (route = routes; route; route = route->next) + if (route->sig == sig) callback(&route->addr,route->mask,user); +} + + +static SIGNALING_ENTITY *dfl_find_route(struct sockaddr_atmsvc *from, struct sockaddr_atmsvc *to,struct atm_qos *qos) { ROUTE *best,*route; @@ -63,3 +73,16 @@ } return best->sig; } + + +static void dfl_route_sig(SIGNALING_ENTITY *sig,struct sockaddr_atmpvc *pvc, + int up) +{ + /* do nothing */ +} + + +SIGNALING_ENTITY *(*find_route)(struct sockaddr_atmsvc *from, + struct sockaddr_atmsvc *to,struct atm_qos *qos) = &dfl_find_route; +void (*route_sig)(SIGNALING_ENTITY *sig,struct sockaddr_atmpvc *pvc,int up) = + &dfl_route_sig; diff -ur --new-file old/atm/switch/route.h new/atm/switch/route.h --- old/atm/switch/route.h Wed Apr 15 21:00:48 1998 +++ new/atm/switch/route.h Wed Aug 12 12:33:51 1998 @@ -10,10 +10,39 @@ #include "sig.h" +/* + * PUT_ROUTE is invoked during configuration time to add static routes. + */ + void put_route(struct sockaddr_atmsvc *addr,int addr_mask, SIGNALING_ENTITY *sig); -SIGNALING_ENTITY *find_route(struct sockaddr_atmsvc *from, + +/* + * GET_ROUTES can be invoked to obtain static routes of a signaling entity. A + * non-default routing mechanism may call GET_ROUTES from ROUTE_SIG to retrieve + * pre-configured static routes. + */ + +void get_routes(SIGNALING_ENTITY *sig, + void (*callback)(struct sockaddr_atmsvc *addr,int addr_mask,void *user), + void *user); + +/* + * FIND_ROUTE obtains the signaling entity for calls from FROM to TO with the + * QoS QOS. The default implementation only considers FROM for its routing + * decisions. + */ + +extern SIGNALING_ENTITY *(*find_route)(struct sockaddr_atmsvc *from, struct sockaddr_atmsvc *to,struct atm_qos *qos); +/* + * ROUTE_SIG is invoked whenever a signaling entity becomes operational + * (UP != 0) or when it is shut down (UP == 0). This can be used to initate + * routing protocol activities. + */ + +extern void (*route_sig)(SIGNALING_ENTITY *sig,struct sockaddr_atmpvc *pvc, + int up); #endif diff -ur --new-file old/atm/switch/sig.c new/atm/switch/sig.c --- old/atm/switch/sig.c Tue Aug 4 19:53:55 1998 +++ new/atm/switch/sig.c Wed Aug 12 12:41:30 1998 @@ -15,6 +15,7 @@ #include "dispatch.h" #include "proto.h" #include "sig.h" +#include "route.h" #include "fab.h" @@ -95,8 +96,9 @@ diag(COMPONENT,DIAG_FATAL,"un_attach %s: %s",sig->path,strerror(errno)); send_listen(sig); error = sig_recv(sig,sig_check_listen); - if (!error) dsp_fd_add(sig->s,sig_data,sig); - else diag(COMPONENT,DIAG_FATAL,"listen failed: %s",strerror(error)); + if (error) diag(COMPONENT,DIAG_FATAL,"listen failed: %s",strerror(error)); + dsp_fd_add(sig->s,sig_data,sig); + route_sig(sig,&sig->call->out.pvc,1); } @@ -143,6 +145,7 @@ fab_op(sig->call,RM_CLAIM(_RM_ANY),&qos,up_callback,sig); } else { + route_sig(sig,&sig->call->out.pvc,0); remove_entity(sig); fab_op(sig->call,RM_FREE,NULL,down_callback,NULL); free_call(sig->call); .