OpenBCM V1.07b12 (Linux)

Packet Radio Mailbox

DB0FHN

[JN59NK Nuernberg]

 Login: GUEST





  
DL9SAU > WAMPES   15.09.01 14:24l 489 Lines 13996 Bytes #999 (0) @ DL
BID : DB0TUDGJPDPO
Read: DB1RAS GUEST DL8BCZ DM3TT
Subj: wampes: krnlif.c PF_PACKET fix fuer linux 2.2.x, linux kernel: ax25_encapsulate
Path: DB0AAB<DB0SL<DB0RGB<DB0MRW<DB0ERF<DB0SHG<DB0FC<DB0TUD
Sent: 010915/1209z @:DB0TUD.#SAX.DEU.EU [TCP/IP-NODE DRESDEN] DP6.00 $:DB0TUDGJ

hallo,

wampes hatte seit kernel 2.2.x ein problem mit linux-kernel-AX25-interfaces
wie smX, bpqX, ..  die mit "attach kernel" attached wurden.

krnlif.c nutzte socket(PF_INET, SOCK_PACKET, ..) des kernel 2.0.x, welches
seit 2.2.x als obsolet gilt und zu fehlfunktionen vieler linux programme
fuehrte. die neue empfohlene variante ist PF_PACKET:
socket(PF_PACKET, SOCK_RAW, ..)
der hier vorgestellte patch fixt dieses problem, und andere kleinigkeiten.


btw, user von bpqether, soundmodem, scc, .. linux kernel treibern haben
ein problem, welches bei 6pack.c und mkiss.c bereits behoben ist:

es wird nicht geprueft, ob das ueber das iface empfangene paket bereits
vom type ETH_P_AX25 ist (weil das sendende programm ja seinen eigenen
AX25 stack hat und vollstaendige pakete verschickt). so gelangt dieses
fertige packet falscherweise zusaetzlich zu ax25_encapsulate() in
/usr/src/linux/net/ax25/ax25_ip.c, der dann natuerlich ziemlich irritiert
darueber ist (es ist ja kein IP paket), und dies mit "wrong protocol
type: 0x2..." honoriert.

bis die angesprochenen treiber ihrerseits gefixt sind, empfehle ich,
ax25_ip.c (s.u.) entsprechend anzupassen.

73,
	- thomas


APPENDIX I: wampes krnlif.c patch
---------------------------------

*** src/krnlif.c.orig	Sun Jun 20 21:03:51 1999
--- src/krnlif.c	Sat Sep 15 12:05:15 2001
***************
*** 57,64 ****
--- 57,79 ----
   *
   * This module is Linux specific. SOCK_PACKET is the Linux way to get
   * packets at the raw interface level.
+  *
+  * -D USE_OBSOLETE_SOCK_PACKET because of incompatibilties with kernel 2.2.x
+  *    by thomas <dl9sau>
   */
  
+ #include <linux/version.h>
+ #ifndef KERNEL_VERSION
+ #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+ #endif
+ #ifndef LINUX_VERSION_CODE
+ #define	LINUX_VERSION_CODE KERNEL_VERSION(2,0,0)-1
+ #endif
+ 
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+ #define USE_OBSOLETE_SOCK_PACKET 1
+ #endif
+ 
  #include <sys/types.h>
  
  #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
***************
*** 72,78 ****
--- 87,105 ----
  #include <linux/if_ether.h>
  #include <linux/if_arp.h>
  #include <linux/in.h>
+ #ifndef	USE_OBSOLETE_SOCK_PACKET
+ #include <features.h>    /* for the glibc version number */
+ #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
+ #include <netpacket/packet.h>
+ #include <net/ethernet.h>     /* the L2 protocols */
+ #else
+ #include <asm/types.h>
+ #include <linux/if_packet.h>
+ #include <linux/if_ether.h>   /* The L2 protocols */
+ #endif
+ #endif
  #include <unistd.h>
+ #include <fcntl.h>
  
  #include "global.h"
  #include "mbuf.h"
***************
*** 97,102 ****
--- 124,132 ----
  	struct mbuf *sndq;      /* Transmit queue */
  
  	short oldflags;         /* used to restore the interrupt flags */
+ #ifndef	USE_OBSOLETE_SOCK_PACKET
+ 	int ifindex;	        /* interface index (ifr_ifru.ifru_ivalue) */
+ #endif
  	int proto;              /* protocol to listen for */
  	int promisc;            /* set interface to promiscious mode */
  
***************
*** 113,137 ****
  static int krnlif_up(struct krnlif *ki)
  {
  	struct ifreq ifr;
  	struct sockaddr sa;
  
  	if (ki->fd >= 0)        /* Already UP */
  		return 0;
! 	if ((ki->fd = socket(PF_INET, SOCK_PACKET, ki->proto)) < 0)
  		goto Fail;
  	strcpy(ifr.ifr_name, ki->iface->name);
! 	if (ioctl(ki->fd, SIOCGIFFLAGS, &ifr) < 0)
  		goto Fail;
  	ki->oldflags = ifr.ifr_flags;
  	ifr.ifr_flags |= IFF_UP;
  	if (ki->promisc)
  		ifr.ifr_flags |= IFF_PROMISC;
  	if (ioctl(ki->fd, SIOCSIFFLAGS, &ifr) < 0)
  		goto Fail;
! 	strcpy(sa.sa_data, ki->iface->name);
! 	sa.sa_family = AF_INET;
! 	if (bind(ki->fd, &sa, sizeof(struct sockaddr)) < 0)
! 		goto Fail;
  
  	on_read(ki->fd, (void (*)(void *)) ki->iface->rxproc, ki->iface);
  	return 0;
--- 143,202 ----
  static int krnlif_up(struct krnlif *ki)
  {
  	struct ifreq ifr;
+ #ifdef USE_OBSOLETE_SOCK_PACKET
  	struct sockaddr sa;
+ #else
+ 	struct sockaddr_ll sll;
+ 	struct packet_mreq mr;
+ #endif
  
  	if (ki->fd >= 0)        /* Already UP */
  		return 0;
! #ifdef	USE_OBSOLETE_SOCK_PACKET
! 	if ((ki->fd = socket(PF_INET, SOCK_PACKET, ki->proto)) < 0) {
! #else
! 	if ((ki->fd = socket(PF_PACKET, SOCK_RAW, ki->proto)) < 0) {
! #endif
! 		printf("error in krnlif_up: socket() for %s failed. this should never happen\n", ki->proto);
  		goto Fail;
+ 	}
  	strcpy(ifr.ifr_name, ki->iface->name);
! 	if (ioctl(ki->fd, SIOCGIFFLAGS, &ifr) < 0) {
! 		printf("error in krnlif_up: ioctl(SIOCGIFFLAGS) for %s failed. this should never happen\n", ki->iface->name);
  		goto Fail;
+ 	}
  	ki->oldflags = ifr.ifr_flags;
  	ifr.ifr_flags |= IFF_UP;
  	if (ki->promisc)
  		ifr.ifr_flags |= IFF_PROMISC;
  	if (ioctl(ki->fd, SIOCSIFFLAGS, &ifr) < 0)
+                 goto Fail;
+ #ifdef	USE_OBSOLETE_SOCK_PACKET
+         strcpy(sa.sa_data, ki->iface->name);
+         sa.sa_family = AF_INET;
+         if (bind(ki->fd, &sa, sizeof(struct sockaddr)) < 0)
+                 goto Fail;
+ #else
+ 	memset(&sll, 0, sizeof(sll));
+ 	sll.sll_ifindex = ki->ifindex;
+ 	sll.sll_protocol = ki->proto;
+ 	sll.sll_family = AF_PACKET;
+ 	if (bind(ki->fd, (struct sockaddr *) &sll, sizeof(sll)) < 0) {
+ 		printf("error in krnlif_up: bind() for %s failed. this should never happen.\ndebug: Error %s (%i)\n", ki->iface->name, strerror(errno), errno);
  		goto Fail;
! 	}
! 	memset(&mr, 0, sizeof(&mr));
! 	mr.mr_ifindex = sll.sll_ifindex;
! 	if (ki->promisc) {
! 	  mr.mr_type = PACKET_MR_PROMISC;
! 	}
! 	if (setsockopt(ki->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (char *) &mr, sizeof(mr)) < 0) {
! 		perror("PACKET_ADD_MEMBERSHIP");
! 		printf("error in krnlif_up: setsockopt(SOL_PACKET, PACKET_ADD_MEMBERSHIP) for %s (%d) failed: %s (%i). this should never happen\n", ki->iface->name, ki->ifindex, strerror(errno), errno);
! 			goto Fail;
! 	}
! 	fcntl(ki->fd, F_SETFL, fcntl(ki->fd, F_GETFL, 0) | O_NONBLOCK);
! #endif
  
  	on_read(ki->fd, (void (*)(void *)) ki->iface->rxproc, ki->iface);
  	return 0;
***************
*** 203,224 ****
  	for (bp = ki->sndq; bp; bp = bp->next) {
  		cnt += bp->cnt;
  		if (cnt > sizeof(buf)) {
! 			free_mbuf(&ki->sndq);
  			return;
  		}
  		memcpy(bufp, bp->data, bp->cnt);
  		bufp += bp->cnt;
  	}
  	strncpy(to.sa_data, ki->iface->name, sizeof(to.sa_data));
  	i = sendto(ki->fd, buf, cnt, 0, &to, sizeof(to));
  	if (i >= 0) {
  		ki->txpkts++;
  		ki->txchar += cnt;
! 		free_mbuf(&ki->sndq);
  		return;
  	}
  	if (errno == EMSGSIZE) {
! 		free_mbuf(&ki->sndq);
  		return;
  	}
  	if (errno == EWOULDBLOCK)
--- 268,303 ----
  	for (bp = ki->sndq; bp; bp = bp->next) {
  		cnt += bp->cnt;
  		if (cnt > sizeof(buf)) {
! 			/* dl9sau bugfix: free_p() to free this packet,
! 			 * not free_mbuf(), because ki->sndq must point to the
! 			 * next packet (anext) or point to 0 when no packet
! 			 * is left in the sendqueue.
! 			 */
! 			free_p(&ki->sndq);
  			return;
  		}
  		memcpy(bufp, bp->data, bp->cnt);
  		bufp += bp->cnt;
  	}
+ #ifdef	USE_OBSOLETE_SOCK_PACKET
  	strncpy(to.sa_data, ki->iface->name, sizeof(to.sa_data));
  	i = sendto(ki->fd, buf, cnt, 0, &to, sizeof(to));
+ #else
+ 	/* puh.. thanks to sockaddr_ll, the socket knows about the iface,
+ 	 * and NULL is enough..
+ 	 */
+ 	i = sendto(ki->fd, buf, cnt, 0, NULL, 0);
+ #endif
  	if (i >= 0) {
  		ki->txpkts++;
  		ki->txchar += cnt;
! 		free_p(&ki->sndq);
  		return;
  	}
+ 	perror("krnlif_tx(): sendto()");
+ 	printf("debug: krnlif_tx: sendto() returned %d\n", i);
  	if (errno == EMSGSIZE) {
! 		free_p(&ki->sndq);
  		return;
  	}
  	if (errno == EWOULDBLOCK)
***************
*** 263,279 ****
  	int from_len = sizeof(from);
  	int i;
  	struct mbuf *bp;
  
  	if (!iface || iface->dev < 0 || iface->dev >= KRNLIF_MAX)
  		return;
  	ki = KrnlIf + iface->dev;
  	if (!(bp = alloc_mbuf(ki->iface->mtu+16)))
  		return;
  	i = recvfrom(ki->fd, bp->data, bp->size, 0, &from, &from_len);
  	if (i <= 0) {
- 		if (i < 0 || errno != EWOULDBLOCK)
- 			krnlif_down(ki);
  		free_mbuf(&bp);
  		return;
  	}
  	bp->cnt = i;
--- 342,388 ----
  	int from_len = sizeof(from);
  	int i;
  	struct mbuf *bp;
+ 	int j;
  
  	if (!iface || iface->dev < 0 || iface->dev >= KRNLIF_MAX)
  		return;
  	ki = KrnlIf + iface->dev;
  	if (!(bp = alloc_mbuf(ki->iface->mtu+16)))
  		return;
+ #ifdef	USE_OBSOLETE_SOCK_PACKET
  	i = recvfrom(ki->fd, bp->data, bp->size, 0, &from, &from_len);
+ #else
+ 	i = recvfrom(ki->fd, bp->data, bp->size, 0, NULL, 0);
+ #endif
+ 	if (i < 1+AXALEN*2+1) {
+ 		/* kiss-byte + AX25 frame: is minimal 1+(6call+1pid)*2 + Control-Byte */
+ 	  	// debug: printf("warning: read % bytes. should never happen\n", i);
+ 		// discard silently
+ 	  	free_mbuf(&bp);
+ 	  	return;
+ 	}
+ 
+ #ifndef	notdef
+ 	// debug: dump non ax25-kiss frames
+ 	if (i >= 0 && i < 1+AXALEN*2+1) {
+ 	  	printf("frame dropped: read %d bytes - ", i);
+ 		printf("bp->data: >", bp->data);
+ 		for (j = 0; j < i; j++) {
+ 		  printf("%d: 0x%02x", j, bp->data[j], bp->data[j]);
+ 		  if (j < i-1) printf(", ");
+ 		}
+ 		printf("<\n");
+ 		free_mbuf(&bp);
+ 		return;
+ 	}
+ #endif
+ 
  	if (i <= 0) {
  		free_mbuf(&bp);
+ 		if (i < 0 || errno != EWOULDBLOCK) {
+ 			printf("warning: read %d bytes, cause %s (%i)\n", i, strerror(errno), errno);
+ 			krnlif_down(ki);
+ 		}
  		return;
  	}
  	bp->cnt = i;
***************
*** 338,357 ****
  	struct ifreq ifr;
  	struct sockaddr hw;
  	struct sockaddr_in in;
! 	int fd;
  	struct hwencap *hwe = hwencap;
  
  	if (if_lookup(argv[1]) != NULL) {
! 		printf("Interface %s already exists\n",argv[4]);
  		return -1;
  	}
  	/*
  	 * get parameters of the interface
  	 */
  	if ((fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
  		perror("socket");
  		return -1;
  	}
  	strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));
  	ifr.ifr_addr.sa_family = AF_INET;
  	if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
--- 447,474 ----
  	struct ifreq ifr;
  	struct sockaddr hw;
  	struct sockaddr_in in;
! #ifndef	USE_OBSOLETE_SOCK_PACKET
! 	struct ifreq ifr_h;
! #endif
  	struct hwencap *hwe = hwencap;
+ 	int fd;
  
  	if (if_lookup(argv[1]) != NULL) {
! 		printf("Interface %s already exists\n",argv[1]);
  		return -1;
  	}
  	/*
  	 * get parameters of the interface
  	 */
+ #ifdef	USE_OBSOLETE_SOCK_PACKET
  	if ((fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
+ #else
+ 	if ((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_AX25))) < 0) {
+ #endif
  		perror("socket");
  		return -1;
  	}
+ 
  	strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));
  	ifr.ifr_addr.sa_family = AF_INET;
  	if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
***************
*** 364,369 ****
--- 481,487 ----
  		       in.sin_family);
  		return -1;
  	}
+ #ifdef	USE_OBSOLETE_SOCK_PACKET
  	memcpy(&in, &ifr.ifr_addr, sizeof(in));
  	ifr.ifr_addr.sa_family = AF_UNSPEC;
  	if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
***************
*** 371,376 ****
--- 489,509 ----
  		printf("cannot get hw addr for interface %s\n", argv[1]);
  		return -1;
  	}
+ #endif
+ #ifndef	USE_OBSOLETE_SOCK_PACKET
+ 	strncpy(ifr_h.ifr_name, argv[1], sizeof(ifr_h.ifr_name));
+ 	if (ioctl(fd, SIOCGIFINDEX, &ifr_h) < 0) {
+ 		perror("ioctl (SIOCGIFINDEX)");
+ 		printf("cannot get index of interface %s\n", argv[1]);
+ 		return -1;
+ 	}
+ 	strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));
+ 	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ 		perror("ioctl (SIOCGIHWADDR)");
+ 		printf("cannot get hw addr for interface %s\n", argv[1]);
+ 		return -1;
+ 	}
+ #endif
  	hw = ifr.ifr_hwaddr;
  	for (; (hwe->family != hw.sa_family) && (hwe->encap != NULL); hwe++);
  	if (hwe->family != hw.sa_family) {
***************
*** 390,395 ****
--- 523,529 ----
  		printf("Too many kernel interfaces\n");
  		return -1;
  	}
+ 
  	ki = KrnlIf+dev;
  	/* Create interface structure and fill in details */
  	ifp = (struct iface *)callocw(1,sizeof(struct iface));
***************
*** 415,420 ****
--- 549,557 ----
  
  	ki->fd = -1;
  	ki->iface = ifp;
+ #ifndef	USE_OBSOLETE_SOCK_PACKET
+ 	ki->ifindex = ifr_h.ifr_ifindex;
+ #endif
  	ki->proto = htons(ETH_P_AX25);
  	ki->promisc = !((argc >= 3) && !strcmp(argv[2], "nopromisc"));;
  

APPENDIX II: linux/net/ax25/ax25_ip.c hack
------------------------------------------

[..]
int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
{

 	unsigned char *buff;

	if (type == ETH_P_AX25) {
		/* dl9sau: some drivers are buggy (for e.g. bpqether),
		 * some are ok (mkiss, ..).
		 * since AX25 in AX25 encapsulation does not make sense (there
		 * is even no official AX25 Layer3 PID definition),
		 * it's save to use ETH_P_AX25 as marker that there is
		 * already a valid ax25 header.
		 * the here provided check is, what is actualy done by mkiss
		 * for not entering this function.
		 * we send no debug message, because the use of such interfaces
		 * is valid (for e.g. PF_PACKET attach of programs with own
		 * ax25 stack) and would lead to too many messages.
		 */
	  	return 0;
        }

  	/* header is an AX.25 UI frame from us to them */
	*buff = skb_push(skb, AX25_HEADER_LEN);

  	*buff++ = 0x00;	/* KISS DATA */

	if (daddr != NULL)
		memcpy(buff, daddr, dev->addr_len);	/* Address specified */

  	buff[6] &= ~AX25_CBIT;
  	buff[6] &= ~AX25_EBIT;
  	buff[6] |= AX25_SSSID_SPARE;
  	buff    += AX25_ADDR_LEN;

  	if (saddr != NULL)
  		memcpy(buff, saddr, dev->addr_len);
  	else
  		memcpy(buff, dev->dev_addr, dev->addr_len);

  	buff[6] &= ~AX25_CBIT;
  	buff[6] |= AX25_EBIT;
  	buff[6] |= AX25_SSSID_SPARE;
  	buff    += AX25_ADDR_LEN;

  	*buff++  = AX25_UI;	/* UI */

  	/* Append a suitable AX.25 PID */
  	switch (type) {
  		case ETH_P_IP:
  			*buff++ = AX25_P_IP;
 			break;
  		case ETH_P_ARP:
  			*buff++ = AX25_P_ARP;
  			break;
  		default:
  			printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%02x\n", type);
  			*buff++ = 0;
  			break;
 	}

	if (daddr != NULL)
	  	return AX25_HEADER_LEN;

	return -AX25_HEADER_LEN;	/* Unfinished header */
}
[..]


Read previous mail | Read next mail


 18.05.2024 18:36:19lGo back Go up