[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
ARP fix: ``int op'' to ``u_int16_t op'' in sys/netinet/if_ether.c
- To: bugs_(_at_)_openbsd_(_dot_)_org
- Subject: ARP fix: ``int op'' to ``u_int16_t op'' in sys/netinet/if_ether.c
- From: Marco Munari <mar_(_dot_)_develops_(_at_)_allerta_(_dot_)_it>
- Date: Sat, 25 Feb 2006 02:34:17 +0100
- Face: iVBORw0KGgoAAAANSUhEUgAAADIAAAAYCAMAAACP1l7TAAAAM1BMVEU4AACKbWzcqqerdnJVPDu1jYrTvcPYm5ZkT06EVVLDnp3wv7uUgoL2z85yXl1cMC07Jygn/pCmAAAAAXRSTlMAQObYZgAAAYNJREFUeNqVlIuSKyEIRBVEEZWZ///abXSztVWbujdDKvOyDw0OSUrJs5hZTf8P4XN21e6ZgRH9Qy2Sc9eijhu977sgNNzGWH/l1SDX0ECqhwCjMPM8BVZj/JIPIpOZPQRlK8tB4IEssFWHl4CCHb7UkB/JYhXLm9Hk4bAf7zRY6ixt7GjCvZQrdB6f6XADgnJQwIRFce/XdfUsjcKlNen7QSiLbl12T4fQMid8S2bm3jeyy+qdOc+73GpIGnucNd5K4tJnnfBUE0bu0wyYuMP2Fy8Fgn7lsEk+LXVlQxZ0VVdjJKex1opeqHFdNbZGwKNLmQcRZqGa1WVFB9Ta2bF9SWuZ6qwVqpSMgbBFhWIVsUZoUmpBLGq4Iqo74IeykuHgEkiCZUzaa2iArNcrpXgufAbMsFlR2Bkia7ItDgPkZwRahGxC9hux7wWiX3MZ/b+Zzm9E3o7uu/kMJD9Gov2UzdLHYTt/lseIP3AhOz9leYLkfWZ7WFc08zkyX/8enyNx+AKHCRJJH5wbuAAAAABJRU5ErkJggg==
- Keywords: ARP fix, gcc 3.3.5 bug, Marco Munari da Castelfranco Veneto
- Supersedes: <ywmzmkm3nhy.fsf@nb.mar.mm>
- Supersedes: <ywmek1sit3r.fsf@nb.mar.mm>
>Submitter-Id: net
>Originator: Marco Munari http://mm.homeunix.org:8380/marcomunari/
>Organization: allerta.it
>Synopsis:
uninitialized int assigned as short possibly inhibit ARP
to work properly
(seems a gcc bug, but kernel code facilitate it)
>Severity:
serious
>Priority:
low
>Category:
kernel, system
>Class:
sw-bug
>Release:
ALL (cvs current, since 18-Oct-95)
>Environment:
System : OpenBSD 3.8
Architecture: OpenBSD.i386
Machine : i386
>Description:
In one of my OpenBSD systems ARP didn't work, the reason -common to OpenBSD-
was the following:
I noticed that op in if_ether.c is more natural of type u_int16_t,
insted of int
file,version:line:
sys/netinet/if_ether.c,1.1:531: int op;
===
sys/netinet/if_ether.c,1.1:534: op = ntohs(ea->arp_op);
it heppen that op was -741081087 (= D3D40001) instead of 1
(in some 16-bit-also architectures such as AMD64, the highter
half of 32 bit is never initialized, but used in comparisons)
code generated by gcc:
d025e16c: 0f b7 41 06 movzwl 0x6(%ecx),%eax
d025e170: 86 c4 xchg %al,%ah
;rorw $8,%ax in ~i486+ w pipelines
;(xchg insted of rotate by 8 bits
; is efficient only in old CPU
; w/o pipelines)
d025e172: 66 89 45 b0 mov %ax,0xffffffb0(%ebp)
last mov instruction is inapropriate for signed int,
this seems a compiler(gcc-3.3.5) bug, above instruction should be:
movzwl %ax,0xffffffb0(%ebp)
I'll have the opportunity to verify again more carefully the gcc generated
code (currently I'm physically 600km far from the fixed machine that
didn't work properly), the ``optimization'' flag -O2 produced
very different code each minimal changment in the source, I have some
dubts for now, except that
(int)op was -741081087 and ARP didn't work for the wrong op
assignment in that machine.
PS: an explicit assigment op = (int)ntohs(ea->arp_op); seem to produce
also the wrong code (but I didn't run the code in this second case).
op = 0x0000ffff & ntohs(ea->arp_op); // solves (but is undesirable)
to be precise my sys/arch/i386/include/endian.h contains:
#define __swap16md(x) ({ \
u_int16_t __swap16md_x = (x); \
__asm ("xchgb %b1, %h1" : "+Q" (__swap16md_x)); /* changed */ \
__swap16md_x; \
})
but the result is the same with the original line
__asm ("rorw $8, %w1" : "+r" (__swap16md_x)); \
op nature is u_int16_t as the field ar_op alias arp_op in the structure.
if_ether.h:
/*
* Ethernet Address Resolution Protocol.
*
* See RFC 826 for protocol description. Structure below is adapted
* to resolving internet addresses. Field names used correspond to
* RFC 826.
*/
struct ether_arp {
struct arphdr ea_hdr; /* fixed-size header */
...
};
...
#define arp_op ea_hdr.ar_op
...
if_arp.h:
struct arphdr {
...
u_int16_t ar_op; /* one of: */
=========
#define ARPOP_REQUEST 1 /* request to resolve address */
#define ARPOP_REPLY 2 /* response to previous request */
#define ARPOP_REVREQUEST 3 /* request protocol address given hardware */
#define ARPOP_REVREPLY 4 /* response giving protocol address */
#define ARPOP_INVREQUEST 8 /* request to identify peer */
#define ARPOP_INVREPLY 9 /* response identifying peer */
};
...
>How-To-Repeat:
ARP didn't work on the following architecture
compiler_(_at_)_xsile:/usr/src/sys/arch/i386/compile/MM4C
cpu0: AMD Athlon(tm) 64 Processor 3000+ ("AuthenticAMD" 686-class, 512KB L2 cache) 1.81 GHz
cpu0: FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,SSE3
cpu0: AMD Powernow: TS FID VID TTP TM STC
cpu0: AMD Cool`n'Quiet K8 available states (31100,56000)
real mem = 3220742144 (3145256K)
....
sk0 at skc0 port A, address 00:14:85:22:..:..
eephy0 at sk0 phy 0: Marvell 88E1011 Gigabit PHY, rev. 5
pchb1 at pci0 dev 24 function 0 "AMD AMD64 HyperTransport" rev 0x00
pchb2 at pci0 dev 24 function 1 "AMD AMD64 Address Map" rev 0x00
pchb3 at pci0 dev 24 function 2 "AMD AMD64 DRAM Cfg" rev 0x00
pchb4 at pci0 dev 24 function 3 "AMD AMD64 Misc Cfg" rev 0x00
Reading specs from /usr/lib/gcc-lib/i386-unknown-openbsd3.8/3.3.5/specs
Configured with:
Thread model: single
gcc version 3.3.5 (propolice)
relevant gcc flags used -O2 -os
>Fix:
in function in_arpinput() replace
int op;
with
u_int16_t op;
but a possible short int to int assignment bug concerning at least gcc with
amd64 in compatible mode.
my more rich diff for the involved files (including minor fixes for CARP
and a more efficient htonl/ntohl for i486+ architectures in endian.h)
is here:
http://www.allerta.it/pub/improvements/openbsd/kernel/if_ether_plus_endian.diff
All the best,
MARco
--
x(t),y(t) = th(3t-34.5)*e^[-(3t-34.5)^2]/2-4.3+e^(-1.8/t^2)/(.8*atg(t-
3)+2)(t-1.8)-.3th(5t-42.5),(1.4e^[-(3t-34.5)^2]+1-sgn[|t-8.5|-.5]*1.5*
|sin(pi*t)|^[2e^(-(t-11.5)^2)+.5+e^(-(.6t-3.3)^2)])/(.5+t)+1 ; 0<t<14
http://www.allerta.it/
Visit your host, monkey.org