diff -uNr linux-ftpd-0.17/ftpd/ftpd.c linux-ftpd-0.17.acme/ftpd/ftpd.c
--- linux-ftpd-0.17/ftpd/ftpd.c	Sun Jul 23 00:34:56 2000
+++ linux-ftpd-0.17.acme/ftpd/ftpd.c	Sun Dec  2 03:07:07 2001
@@ -93,6 +93,10 @@
 #include <util.h>
 #include <err.h>
 #else
+#define AF_LLC 26
+#include <net/if.h>
+#include <linux/llc.h>
+#include <netinet/ether.h>
 #include <grp.h>       /* for initgroups() */
 /* #include <sys/file.h>  * for L_SET et al. * <--- not used? */
 /*typedef int64_t quad_t;*/
@@ -140,11 +144,17 @@
 extern	char cbuf[];
 
 struct	sockaddr_in server_addr;
-struct	sockaddr_in ctrl_addr;
-struct	sockaddr_in data_source;
+static struct {
+	int addrlen;
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in inet;
+		struct sockaddr_llc llc;
+	} addr;
+} pasv_addr, ctrl_addr;
 struct	sockaddr_in data_dest;
 struct	sockaddr_in his_addr;
-struct	sockaddr_in pasv_addr;
+struct	sockaddr_in data_source;
 
 int	daemon_mode = 0;
 int	data;
@@ -262,6 +272,18 @@
 
 void logxfer __P((const char *, off_t, time_t));
 
+static int get_hwaddr(int skfd, char* ifname, unsigned char* dest)
+{
+	struct ifreq ifr;
+
+	strcpy(ifr.ifr_name, ifname);
+	if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
+		memset(dest, 0, IFHWADDRLEN);
+	else
+		memcpy(dest, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
+}
+
+
 #ifdef __linux__
 static void warnx(const char *format, ...) 
 {
@@ -294,9 +316,11 @@
 	socklen_t addrlen;
 	char *cp, line[LINE_MAX];
 	FILE *fd;
-	const char *argstr = "AdDhlMSt:T:u:UvP";
+	const char *argstr = "AdDhlLMSt:T:u:UvP";
 	struct hostent *hp;
 
+	pasv_addr.addr.sa.sa_family = ctrl_addr.addr.sa.sa_family = AF_INET;
+	pasv_addr.addrlen = ctrl_addr.addrlen = sizeof(struct sockaddr_in);
 #ifdef __linux__
 	initsetproctitle(argc, argv, envp);
 	srandom(time(NULL)^(getpid()<<8));
@@ -350,6 +374,12 @@
 			logging++;	/* > 1 == extra logging */
 			break;
 
+		case 'L':
+			ctrl_addr.addr.sa.sa_family =
+				pasv_addr.addr.sa.sa_family = AF_LLC;
+			ctrl_addr.addrlen =
+				pasv_addr.addrlen = sizeof(struct sockaddr_llc);
+			break;
 		case 'M':
 			multihome = 1;
 			break;
@@ -492,8 +522,8 @@
 	if (signal(SIGURG, myoob) == SIG_ERR)
 		syslog(LOG_ERR, "signal: %m");
 
-	addrlen = sizeof(ctrl_addr);
-	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
+	addrlen = ctrl_addr.addrlen;
+	if (getsockname(0, (struct sockaddr *)&ctrl_addr.addr, &addrlen) < 0) {
 		syslog(LOG_ERR, "getsockname (%s): %m", argv[0]);
 		exit(1);
 	}
@@ -502,7 +532,7 @@
 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
 #endif
-	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
+	data_source.sin_port = htons(ntohs(ctrl_addr.addr.inet.sin_port) - 1);
 
 	/* Try to handle urgent data inline */
 #ifdef SO_OOBINLINE
@@ -555,13 +585,14 @@
 		strcpy(hostname, hp->h_name);
 
 	if (multihome) {
-		hp = gethostbyaddr((char *) &ctrl_addr.sin_addr,
+		hp = gethostbyaddr((char *) &ctrl_addr.addr.inet.sin_addr,
 		    sizeof (struct in_addr), AF_INET);
 		if (hp != NULL) {
 			strcpy(dhostname, hp->h_name);
 		} else {
 			/* Default. */
-			strcpy(dhostname, inet_ntoa(ctrl_addr.sin_addr));
+			strcpy(dhostname,
+			       inet_ntoa(ctrl_addr.addr.inet.sin_addr));
 		}
 	}
 
@@ -1178,7 +1209,7 @@
 	data_source.sin_len = sizeof(struct sockaddr_in);
 #endif
 	data_source.sin_family = AF_INET;
-	data_source.sin_addr = ctrl_addr.sin_addr;
+	data_source.sin_addr = ctrl_addr.addr.inet.sin_addr;
 	for (tries = 1; ; tries++) {
 		if (bind(s, (struct sockaddr *)&data_source,
 		    sizeof(data_source)) >= 0)
@@ -1241,7 +1272,7 @@
 	} else
 		sizebuf[0] = '\0';
 	if (pdata >= 0) {
-		struct sockaddr_in from;
+		struct sockaddr_llc from;
 		int s;
 		socklen_t fromlen = sizeof(from);
 
@@ -1255,6 +1286,7 @@
 			pdata = -1;
 			return (NULL);
 		}
+#if 0
 		if (ntohs(from.sin_port) < IPPORT_RESERVED) {
 			perror_reply(425, "Can't build data connection");
 			(void) close(pdata);
@@ -1269,6 +1301,7 @@
 			pdata = -1;
 			return (NULL);
 		}
+#endif
 		(void) close(pdata);
 		pdata = s;
 #ifdef IP_TOS
@@ -1304,13 +1337,13 @@
 	 */
 	if (ntohs(data_dest.sin_port) < IPPORT_RESERVED ||
 	    ntohs(data_dest.sin_port) == 2049) {		/* XXX */
-		perror_reply(425, "Can't build data connection");
+		perror_reply(425, "Can't build data connection 1");
 		(void) fclose(file);
 		data = -1;
 		return NULL;
 	}
 	if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) {
-		perror_reply(435, "Can't build data connection");
+		perror_reply(435, "Can't build data connection 2");
 		(void) fclose(file);
 		data = -1;
 		return NULL;
@@ -1322,7 +1355,7 @@
 			retry += swaitint;
 			continue;
 		}
-		perror_reply(425, "Can't build data connection");
+		perror_reply(425, "Can't build data connection 3");
 		(void) fclose(file);
 		data = -1;
 		return (NULL);
@@ -1343,6 +1376,7 @@
 	int c, cnt, filefd, netfd;
 	char *buf, *bp;
 	size_t len,size;
+	int error;
 
 	transflag++;
 	if (setjmp(urgcatch)) {
@@ -1355,9 +1389,12 @@
 		while ((c = getc(instr)) != EOF) {
 			byte_count++;
 			if (c == '\n') {
-				if (ferror(outstr))
+				if (ferror(outstr)) {
+					error = 111;
 					goto data_err;
+				}
 				(void) putc('\r', outstr);
+				fflush(outstr);
 			}
 			(void) putc(c, outstr);
 		}
@@ -1365,8 +1402,10 @@
 		transflag = 0;
 		if (ferror(instr))
 			goto file_err;
-		if (ferror(outstr))
+		if (ferror(outstr)) {
+			error = 222;
 			goto data_err;
+		}
 		reply(226, "Transfer complete.");
 		return;
 
@@ -1390,7 +1429,7 @@
 			bp = buf;
 			len = filesize;
 			do {
-				cnt = write(netfd, bp, len);
+				cnt = write(netfd, bp, 1400);
 				len -= cnt;
 				bp += cnt;
 				if (cnt > 0) byte_count += cnt;
@@ -1398,14 +1437,19 @@
 
 			transflag = 0;
 			munmap(buf, (size_t)filesize);
-			if (cnt < 0)
+			if (cnt < 0) {
+				error = cnt;
 				goto data_err;
+			}
 			reply(226, "Transfer complete.");
 			return;
 		}
 
 oldway:
-		size = blksize * 16; 
+		if (pasv_addr.addr.sa.sa_family == AF_LLC)
+			size = 1400;
+		else
+			size = blksize * 16; 
 	
 		if ((buf = malloc(size)) == NULL) {
 			transflag = 0;
@@ -1434,6 +1478,7 @@
 		if (cnt != 0) {
 			if (cnt < 0)
 				goto file_err;
+			error = 444;
 			goto data_err;
 		}
 		reply(226, "Transfer complete.");
@@ -1446,7 +1491,7 @@
 
 data_err:
 	transflag = 0;
-	perror_reply(426, "Data connection");
+	reply(426, "Data Connection %d %s", error, strerror(errno));
 	return;
 
 file_err:
@@ -1462,7 +1507,7 @@
  */
 static int receive_data(FILE *instr, FILE *outstr)
 {
-	int c;
+	int c, error = 0;
 	int cnt;
 	volatile int bare_lfs = 0;
 	char buf[BUFSIZ];
@@ -1480,7 +1525,7 @@
 
 		do {
 			(void) alarm ((unsigned) timeout);
-			cnt = read(fileno(instr), buf, sizeof(buf));
+			cnt = read(fileno(instr), buf, 1400);
 			(void) alarm (0);
 
 			if (cnt > 0) {
@@ -1489,8 +1534,10 @@
 				byte_count += cnt;
 			}
 		} while (cnt > 0);
-		if (cnt < 0)
+		if (cnt < 0) {
+			error = 11;
 			goto data_err;
+		}
 		transflag = 0;
 		return (0);
 
@@ -1505,8 +1552,10 @@
 			if (c == '\n')
 				bare_lfs++;
 			while (c == '\r') {
-				if (ferror(outstr))
+				if (ferror(outstr)) {
+					error = 22;
 					goto data_err;
+				}
 				if ((c = getc(instr)) != '\n') {
 					(void) putc ('\r', outstr);
 					if (c == '\0' || c == EOF)
@@ -1517,8 +1566,10 @@
 	contin2:	;
 		}
 		fflush(outstr);
-		if (ferror(instr))
+		if (ferror(instr)) {
+			error =  33;
 			goto data_err;
+		}
 		if (ferror(outstr))
 			goto file_err;
 		transflag = 0;
@@ -1537,7 +1588,7 @@
 
 data_err:
 	transflag = 0;
-	perror_reply(426, "Data Connection");
+	reply(426, "Data Connection %d %s", error, strerror(errno));
 	return (-1);
 
 file_err:
@@ -1611,7 +1662,7 @@
 		printf("     Data connection open\r\n");
 	else if (pdata != -1) {
 		printf("     in Passive mode");
-		sn = &pasv_addr;
+		sn = &pasv_addr.addr;
 		goto printaddr;
 	} else if (usedefault == 0) {
 		printf("     PORT");
@@ -1922,7 +1973,7 @@
 	}
 	if (pdata >= 0)
 		close(pdata);
-	pdata = socket(AF_INET, SOCK_STREAM, 0);
+	pdata = socket(pasv_addr.addr.sa.sa_family, SOCK_STREAM, 0);
 	if (pdata < 0) {
 		perror_reply(425, "Can't open passive connection");
 		return;
@@ -1938,10 +1989,10 @@
 #define FTP_DATA_TOP    44999
 	if (high_data_ports) {
 		for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) {
-			pasv_addr = ctrl_addr;
-			pasv_addr.sin_port = htons(port);
-			if (bind(pdata, (struct sockaddr *) &pasv_addr,
-				 sizeof(pasv_addr)) == 0)
+			pasv_addr.addr = ctrl_addr.addr;
+			pasv_addr.addr.inet.sin_port = htons(port);
+			if (bind(pdata, (struct sockaddr *) &pasv_addr.addr,
+				 pasv_addr.addrlen) == 0)
 				break;
 			if (errno != EADDRINUSE)
 				goto pasv_error;
@@ -1952,20 +2003,29 @@
 	else
 #endif
 	{
-		pasv_addr = ctrl_addr;
-		pasv_addr.sin_port = 0;
-		if (bind(pdata, (struct sockaddr *)&pasv_addr,
-			 sizeof(pasv_addr)) < 0)
+		pasv_addr.addr = ctrl_addr.addr;
+		if (pasv_addr.addr.sa.sa_family == AF_INET)
+			pasv_addr.addr.inet.sin_port = 0;
+		else if (pasv_addr.addr.sa.sa_family == AF_LLC) {
+			memset(&pasv_addr.addr.llc, 0,
+			       sizeof(pasv_addr.addr.llc));
+			pasv_addr.addr.sa.sa_family = AF_LLC;
+			pasv_addr.addr.llc.sllc_arphrd = ARPHRD_ETHER;
+			get_hwaddr(pdata, "eth0", pasv_addr.addr.llc.sllc_smac);
+			pasv_addr.addr.llc.sllc_ssap = 92;
+		}
+		if (bind(pdata, (struct sockaddr *)&pasv_addr.addr,
+			 pasv_addr.addrlen) < 0)
 			goto pasv_error;
 	}
 
-	len = sizeof(pasv_addr);
-	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
+	len = pasv_addr.addrlen;
+	if (getsockname(pdata, (struct sockaddr *) &pasv_addr.addr, &len) < 0)
 		goto pasv_error;
 	if (listen(pdata, 1) < 0)
 		goto pasv_error;
-	a = (char *) &pasv_addr.sin_addr;
-	p = (char *) &pasv_addr.sin_port;
+	a = (char *) &pasv_addr.addr.inet.sin_addr;
+	p = (char *) &pasv_addr.addr.inet.sin_port;
 
 #define UC(b) (((int) b) & 0xff)
 
