* Copyright (c) 1982, 1986, 1988 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)if_ethersubr.c 7.2 (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"
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
)
register struct ifnet
*ifp
;
register struct mbuf
*m
= m0
;
struct mbuf
*mcopy
= (struct mbuf
*)0;
register struct ether_header
*eh
;
#define ac ((struct arpcom *)ifp)
if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
)) {
if (ifp
->if_flags
& IFF_SIMPLEX
&& dst
->sa_family
!= AF_UNSPEC
&&
!bcmp((caddr_t
)edst
, (caddr_t
)etherbroadcastaddr
, sizeof (edst
)))
mcopy
= m_copy(m
, 0, (int)M_COPYALL
);
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
);
*mtod(m
, u_short
*) = htons((u_short
)ETHERTYPE_IP
);
*(mtod(m
, u_short
*) + 1) = htons((u_short
)m
->m_len
);
if (!bcmp((caddr_t
)edst
, (caddr_t
)&ns_thishost
, sizeof(edst
)))
return(looutput(&loif
, m
, dst
));
bcopy((caddr_t
)&(((struct sockaddr_ns
*)dst
)->sns_addr
.x_host
),
(caddr_t
)edst
, sizeof (edst
));
if ((ifp
->if_flags
& IFF_SIMPLEX
) && (*edst
& 1))
mcopy
= m_copy(m
, 0, (int)M_COPYALL
);
if ((ret
= iso_tryloopback(m
, (struct sockaddr_iso
*)dst
)) >= 0)
ret
= iso_snparesolve(ifp
, (struct sockaddr_iso
*)dst
,
m_freem(m
); /* Not Resolved */
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);
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.
* 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)
error
= (*ifp
->if_start
)(ifp
);
(void) looutput(&loif
, mcopy
, dst
);
* Pull packet off interface. Off is nonzero if packet
* has trailing header; we still have to drop
* the type and length which are at the front of any trailer data.
register struct ether_header
*eh
;
register struct ifqueue
*inq
;
if (bcmp((caddr_t
)etherbroadcastaddr
, (caddr_t
)eh
->ether_dhost
,
sizeof(etherbroadcastaddr
)) == 0)
else if (eh
->ether_dhost
[0] & 1)
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
)) {
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];