Subject: kern/31368: Linux compatibility raw inet protocol handling changes
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Cliff Wright <cliff@vixen.snipe444.org>
List: netbsd-bugs
Date: 09/21/2005 23:17:00
>Number: 31368
>Category: kern
>Synopsis: Linux compatibility raw inet protocol handling changes
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Sep 21 23:17:00 +0000 2005
>Originator: Cliff Wright
>Release: NetBSD 2.0_BETA
>Organization:
>Environment:
System: NetBSD vixen 2.0_BETA NetBSD 2.0_BETA (vixen) #2: Tue Jun 7 16:15:17 PDT 2005 cliff@vixen:/usr/src/sys/arch/i386/compile/vixen i386
Architecture: i386
Machine: i386
>Description:
When running a vendor network analysis program in Linux
compatibility mode, some missing features, and problems
were observed. A patch is included that fixes these.
1. The rarely used get interface mtu (SIOCGIFMTU) was
not implemented.
2. The raw inet protocol option header include (IP_HDRINCL)
was not implemented.
3. When using bind on a raw inet socket, Linux ignores some
bytes that BSD does not, so needed to adjust these bytes
for the BSD call.
4. When using the header include option, BSD has 2 fields of
the packet in host byte order, whereas Linux does not,
so may need to adjust these fields.
>How-To-Repeat:
>Fix:
--- src/sys/compat/linux/common/linux_socket.h.orig 2003-07-27 12:30:03.000000000 -0700
+++ src/sys/compat/linux/common/linux_socket.h 2005-09-20 14:08:13.000000000 -0700
@@ -110,6 +110,7 @@
#define LINUX_IP_TOS 1
#define LINUX_IP_TTL 2
+#define LINUX_IP_HDRINCL 3
#define LINUX_IP_MULTICAST_IF 32
#define LINUX_IP_MULTICAST_TTL 33
#define LINUX_IP_MULTICAST_LOOP 34
--- src/sys/compat/linux/common/linux_sockio.h.orig 2000-12-22 03:24:43.000000000 -0800
+++ src/sys/compat/linux/common/linux_sockio.h 2005-09-19 14:41:11.000000000 -0700
@@ -47,6 +47,7 @@
#define LINUX_SIOCGIFDSTADDR _LINUX_IO(0x89, 0x17)
#define LINUX_SIOCGIFBRDADDR _LINUX_IO(0x89, 0x19)
#define LINUX_SIOCGIFNETMASK _LINUX_IO(0x89, 0x1b)
+#define LINUX_SIOCGIFMTU _LINUX_IO(0x89, 0x21)
#define LINUX_SIOCADDMULTI _LINUX_IO(0x89, 0x31)
#define LINUX_SIOCDELMULTI _LINUX_IO(0x89, 0x32)
#define LINUX_SIOCGIFHWADDR _LINUX_IO(0x89, 0x27)
--- src/sys/compat/linux/common/linux_socket.c.orig 2003-10-25 11:38:42.000000000 -0700
+++ src/sys/compat/linux/common/linux_socket.c 2005-09-21 14:56:05.000000000 -0700
@@ -64,6 +64,10 @@
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netinet/in.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#endif
#include <netinet/tcp.h>
#include <sys/mount.h>
#include <sys/proc.h>
@@ -385,10 +389,41 @@
struct sockaddr *sa;
int error;
caddr_t sg = stackgap_init(p, 0);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ struct file *fp;
+#endif
if ((error = linux_sa_get(p, &sg, &sa, SCARG(uap, to), &tolen)))
return (error);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* For raw inet header included data, BSD has 2 fields
+ * in host byte order that Linux does not, so need to
+ * adjust for this. cliff
+ */
+
+ if( sa->sa_family == AF_INET &&
+ getsock(p->p_fd, SCARG(uap, s), &fp) == 0) {
+ if(((struct socket *)fp->f_data)->so_type == SOCK_RAW) {
+ struct mbuf *m;
+
+ error = sogetopt((struct socket *)fp->f_data,
+ IPPROTO_IP, IP_HDRINCL, &m);
+ if(!error && m != NULL) {
+ if(*mtod(m, int *)) {
+ struct ip *ip_head;
+
+ ip_head = (struct ip *)
+ SCARG(uap, msg);
+ NTOHS(ip_head->ip_len);
+ NTOHS(ip_head->ip_off);
+ }
+ m_free(m);
+ }
+ }
+ FILE_UNUSE(fp, p);
+ }
+#endif
SCARG(&bsa, to) = sa;
} else
SCARG(&bsa, to) = NULL;
@@ -917,6 +952,8 @@
return IP_TOS;
case LINUX_IP_TTL:
return IP_TTL;
+ case LINUX_IP_HDRINCL:
+ return IP_HDRINCL;
case LINUX_IP_MULTICAST_TTL:
return IP_MULTICAST_TTL;
case LINUX_IP_MULTICAST_LOOP:
@@ -1275,6 +1312,9 @@
case LINUX_SIOCGIFNETMASK:
SCARG(&ia, com) = OSIOCGIFNETMASK;
break;
+ case LINUX_SIOCGIFMTU:
+ SCARG(&ia, com) = SIOCGIFMTU;
+ break;
case LINUX_SIOCADDMULTI:
SCARG(&ia, com) = SIOCADDMULTI;
break;
@@ -1374,11 +1414,12 @@
struct proc *p = l->l_proc;
int error, namlen;
struct sys_bind_args bsa;
+ struct sockaddr *sa;
+ struct file *fp;
namlen = SCARG(uap, namelen);
SCARG(&bsa, s) = SCARG(uap, s);
if (SCARG(uap, name)) {
- struct sockaddr *sa;
caddr_t sg = stackgap_init(p, 0);
error = linux_sa_get(p, &sg, &sa, SCARG(uap, name), &namlen);
@@ -1390,6 +1431,20 @@
SCARG(&bsa, name) = NULL;
SCARG(&bsa, namelen) = namlen;
+ /* For raw inet sockets Linux only looks at 4 byte inet address,
+ * BSD looks at full address, so have to clean up the address
+ * for BSD. cliff
+ */
+ if( sa->sa_family == AF_INET &&
+ getsock(p->p_fd, SCARG(uap, s), &fp) == 0) {
+ if(((struct socket *)fp->f_data)->so_type == SOCK_RAW) {
+ int i;
+ sa->sa_data[0] = sa->sa_data[1] = 0;
+ for (i = 0; i < 8; i++) sa->sa_data[i + 6] = 0;
+ }
+ FILE_UNUSE(fp, p);
+ }
+
return (sys_bind(l, &bsa, retval));
}
>Unformatted: