* Copyright (c) 1982, 1989 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)if_ethersubr.c 7.11 (Berkeley) %G%
#include "machine/mtpr.h"
#include "../netinet/in.h"
#include "../netinet/in_var.h"
#include "../netinet/if_ether.h"
#include "../netns/ns_if.h"
#include "../netiso/argo_debug.h"
#include "../netiso/iso.h"
#include "../netiso/iso_var.h"
#include "../netiso/iso_snpac.h"
u_char etherbroadcastaddr
[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
extern struct ifnet loif
;
* Ethernet output routine.
* Encapsulate a packet of type family for the local net.
* Use trailer local net encapsulation if enough data in first
* packet leaves a multiple of 512 bytes of data in remainder.
* Assumes that ifp is actually pointer to arpcom structure.
ether_output(ifp
, m0
, dst
, rt
)
register struct ifnet
*ifp
;
register struct mbuf
*m
= m0
;
struct mbuf
*mcopy
= (struct mbuf
*)0;
register struct ether_header
*eh
;
int usetrailers
, off
, len
= m
->m_pkthdr
.len
;
extern struct timeval time
;
#define ac ((struct arpcom *)ifp)
if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
)) {
ifp
->if_lastchange
= time
;
switch (dst
->sa_family
) {
idst
= ((struct sockaddr_in
*)dst
)->sin_addr
;
if (!arpresolve(ac
, m
, &idst
, edst
, &usetrailers
))
return (0); /* if not yet resolved */
if ((ifp
->if_flags
& IFF_SIMPLEX
) && (*edst
& 1))
mcopy
= m_copy(m
, 0, (int)M_COPYALL
);
off
= m
->m_pkthdr
.len
- m
->m_len
;
if (usetrailers
&& off
> 0 && (off
& 0x1ff) == 0 &&
(m
->m_flags
& M_EXT
) == 0 &&
m
->m_data
>= m
->m_pktdat
+ 2 * sizeof (u_short
)) {
type
= ETHERTYPE_TRAIL
+ (off
>>9);
m
->m_data
-= 2 * sizeof (u_short
);
m
->m_len
+= 2 * sizeof (u_short
);
len
+= 2 * sizeof (u_short
);
*mtod(m
, u_short
*) = htons((u_short
)ETHERTYPE_IP
);
*(mtod(m
, u_short
*) + 1) = htons((u_short
)m
->m_len
);
bcopy((caddr_t
)&(((struct sockaddr_ns
*)dst
)->sns_addr
.x_host
),
(caddr_t
)edst
, sizeof (edst
));
if (!bcmp((caddr_t
)edst
, (caddr_t
)&ns_thishost
, sizeof(edst
)))
return (looutput(ifp
, m
, dst
, rt
));
if ((ifp
->if_flags
& IFF_SIMPLEX
) && (*edst
& 1))
mcopy
= m_copy(m
, 0, (int)M_COPYALL
);
if (rt
&& rt
->rt_gateway
&& (rt
->rt_flags
& RTF_UP
)) {
if (rt
->rt_flags
& RTF_GATEWAY
) {
rt
= (struct rtentry
*)rt
->rt_llinfo
;
register struct sockaddr_dl
*sdl
=
(struct sockaddr_dl
*)rt
->rt_gateway
;
if (sdl
&& sdl
->sdl_family
== AF_LINK
bcopy(LLADDR(sdl
), (char *)edst
,
if ((error
= iso_snparesolve(ifp
, (struct sockaddr_iso
*)dst
,
(char *)edst
, &snpalen
)) > 0)
goto bad
; /* Not Resolved */
if ((ifp
->if_flags
& IFF_SIMPLEX
) && (*edst
& 1) &&
(mcopy
= m_copy(m
, 0, (int)M_COPYALL
))) {
M_PREPEND(mcopy
, sizeof (*eh
), M_DONTWAIT
);
eh
= mtod(mcopy
, struct ether_header
*);
(caddr_t
)eh
->ether_dhost
, sizeof (edst
));
bcopy((caddr_t
)ac
->ac_enaddr
,
(caddr_t
)eh
->ether_shost
, sizeof (edst
));
M_PREPEND(m
, 3, M_DONTWAIT
);
l
= mtod(m
, struct llc
*);
l
->llc_dsap
= l
->llc_ssap
= LLC_ISO_LSAP
;
printf("unoutput: sending pkt to: ");
printf("%x ", edst
[i
] & 0xff);
* This is IEEE 802.3 -- the Ethernet `type' field is
* really a `length' field.
bcopy((caddr_t
)dst
->sa_data
, (caddr_t
)edst
, sizeof(edst
));
eh
= (struct ether_header
*)dst
->sa_data
;
bcopy((caddr_t
)eh
->ether_dhost
, (caddr_t
)edst
, sizeof (edst
));
printf("%s%d: can't handle af%d\n", ifp
->if_name
, ifp
->if_unit
,
* Packet to be sent as trailer: move first packet
* (control information) to end of chain.
(void) looutput(ifp
, mcopy
, dst
, rt
);
* Add local net header. If no space in first mbuf,
M_PREPEND(m
, sizeof (struct ether_header
), M_DONTWAIT
);
eh
= mtod(m
, struct ether_header
*);
type
= htons((u_short
)type
);
bcopy((caddr_t
)&type
,(caddr_t
)&eh
->ether_type
,
bcopy((caddr_t
)edst
, (caddr_t
)eh
->ether_dhost
, sizeof (edst
));
bcopy((caddr_t
)ac
->ac_enaddr
, (caddr_t
)eh
->ether_shost
,
sizeof(eh
->ether_shost
));
* Queue message on interface, and start output if interface
if (IF_QFULL(&ifp
->if_snd
)) {
IF_ENQUEUE(&ifp
->if_snd
, m
);
if ((ifp
->if_flags
& IFF_OACTIVE
) == 0)
ifp
->if_obytes
+= len
+ sizeof (struct ether_header
);
* Process a received Ethernet packet;
* the packet is in the mbuf chain m without
* the ether header, which is provided separately.
register struct ether_header
*eh
;
register struct ifqueue
*inq
;
ifp
->if_lastchange
= time
;
ifp
->if_ibytes
+= m
->m_pkthdr
.len
+ sizeof (*eh
);
if (bcmp((caddr_t
)etherbroadcastaddr
, (caddr_t
)eh
->ether_dhost
,
sizeof(etherbroadcastaddr
)) == 0)
else if (eh
->ether_dhost
[0] & 1)
if (m
->m_flags
& (M_BCAST
|M_MCAST
))
switch (eh
->ether_type
) {
arpinput((struct arpcom
*)ifp
, m
);
if (eh
->ether_type
> ETHERMTU
)
l
= mtod(m
, struct llc
*);
switch (l
->llc_control
) {
/* LLC_UI_P forbidden in class 1 service */
if ((l
->llc_dsap
== LLC_ISO_LSAP
) &&
(l
->llc_ssap
== LLC_ISO_LSAP
)) {
if (m
->m_pkthdr
.len
> eh
->ether_type
)
m_adj(m
, eh
->ether_type
- m
->m_pkthdr
.len
);
m
->m_data
+= 3; /* XXX */
m
->m_pkthdr
.len
-= 3; /* XXX */
M_PREPEND(m
, sizeof *eh
, M_DONTWAIT
);
*mtod(m
, struct ether_header
*) = *eh
;
l
->llc_dsap
= l
->llc_ssap
= 0;
register struct ether_header
*eh2
;
l
->llc_dsap
= l
->llc_ssap
;
if (m
->m_flags
& (M_BCAST
| M_MCAST
))
bcopy((caddr_t
)ac
->ac_enaddr
,
(caddr_t
)eh
->ether_dhost
, 6);
sa
.sa_family
= AF_UNSPEC
;
eh2
= (struct ether_header
*)sa
.sa_data
;
for (i
= 0; i
< 6; i
++) {
eh2
->ether_shost
[i
] = c
= eh
->ether_dhost
[i
];
eh
->ether_dhost
[i
] = eh
->ether_shost
[i
];
ifp
->if_output(ifp
, m
, &sa
);
* Convert Ethernet address to printable (loggable) representation.
static char digits
[] = "0123456789abcdef";
static char etherbuf
[18];
register char *cp
= etherbuf
;
for (i
= 0; i
< 6; i
++) {
*cp
++ = digits
[*ap
>> 4];
*cp
++ = digits
[*ap
++ & 0xf];