1 /* $NetBSD: if_ecosubr.c,v 1.32 2009/03/18 16:00:22 cegger Exp $ */
4 * Copyright (c) 2001 Ben Harris
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (c) 1982, 1989, 1993
31 * The Regents of the University of California. All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * @(#)if_ethersubr.c 8.2 (Berkeley) 4/4/96
60 #include <sys/cdefs.h>
61 __KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.32 2009/03/18 16:00:22 cegger Exp $");
65 #include "opt_pfil_hooks.h"
67 #include <sys/param.h>
68 #include <sys/errno.h>
69 #include <sys/kernel.h>
70 #include <sys/socket.h>
71 #include <sys/sockio.h>
72 #include <sys/syslog.h>
73 #include <sys/systm.h>
76 #include <net/if_dl.h>
77 #include <net/if_eco.h>
78 #include <net/if_types.h>
79 #include <net/netisr.h>
80 #include <net/route.h>
87 #include <net/ethertypes.h>
88 #include <net/if_arp.h>
89 #include <netinet/in.h>
90 #include <netinet/in_var.h>
93 struct eco_retryparms
{
98 /* Default broadcast address */
99 static const uint8_t eco_broadcastaddr
[] = { 0xff, 0xff };
101 static int eco_output(struct ifnet
*, struct mbuf
*, const struct sockaddr
*,
103 static void eco_input(struct ifnet
*, struct mbuf
*);
104 static void eco_start(struct ifnet
*);
105 static int eco_ioctl(struct ifnet
*, u_long
, void *);
107 static int eco_interestingp(struct ifnet
*ifp
, struct mbuf
*m
);
108 static struct mbuf
*eco_immediate(struct ifnet
*ifp
, struct mbuf
*m
);
109 static struct mbuf
*eco_ack(struct ifnet
*ifp
, struct mbuf
*m
);
111 static void eco_defer(struct ifnet
*, struct mbuf
*, int);
112 static void eco_retry_free(struct eco_retry
*er
);
113 static void eco_retry(void *);
116 eco_ifattach(struct ifnet
*ifp
, const uint8_t *lla
)
118 struct ecocom
*ec
= (void *)ifp
;
120 ifp
->if_type
= IFT_ECONET
;
121 ifp
->if_addrlen
= ECO_ADDR_LEN
;
122 ifp
->if_hdrlen
= ECO_HDR_LEN
;
123 ifp
->if_dlt
= DLT_ECONET
;
124 ifp
->if_mtu
= ECO_MTU
;
126 ifp
->if_output
= eco_output
;
127 ifp
->if_input
= eco_input
;
128 ifp
->if_start
= eco_start
;
129 ifp
->if_ioctl
= eco_ioctl
;
131 /* ifp->if_baudrate...; */
132 if_set_sadl(ifp
, lla
, ECO_ADDR_LEN
, FALSE
);
134 ifp
->if_broadcastaddr
= eco_broadcastaddr
;
136 LIST_INIT(&ec
->ec_retries
);
139 bpfattach(ifp
, ifp
->if_dlt
, ECO_HDR_LEN
);
143 #define senderr(e) do { \
146 } while (/*CONSTCOND*/0)
149 eco_init(struct ifnet
*ifp
)
151 struct ecocom
*ec
= (struct ecocom
*)ifp
;
153 if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
154 ec
->ec_state
= ECO_UNKNOWN
;
159 eco_stop(struct ifnet
*ifp
, int disable
)
161 struct ecocom
*ec
= (struct ecocom
*)ifp
;
163 while (!LIST_EMPTY(&ec
->ec_retries
))
164 eco_retry_free(LIST_FIRST(&ec
->ec_retries
));
168 eco_output(struct ifnet
*ifp
, struct mbuf
*m0
, const struct sockaddr
*dst
,
171 struct eco_header ehdr
, *eh
;
173 struct mbuf
*m
= m0
, *mcopy
= NULL
;
176 int retry_delay
, retry_count
;
178 struct eco_retryparms
*erp
;
183 struct eco_arp
*ecah
;
185 ALTQ_DECL(struct altq_pktattr pktattr
;)
187 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
189 if ((rt
= rt0
) != NULL
) {
190 if ((rt
->rt_flags
& RTF_UP
) == 0) {
191 if ((rt0
= rt
= rtalloc1(dst
, 1)) != NULL
) {
193 if (rt
->rt_ifp
!= ifp
)
194 return (*rt
->rt_ifp
->if_output
)
197 senderr(EHOSTUNREACH
);
199 if ((rt
->rt_flags
& RTF_GATEWAY
) && dst
->sa_family
!= AF_NS
) {
200 if (rt
->rt_gwroute
== 0)
202 if (((rt
= rt
->rt_gwroute
)->rt_flags
& RTF_UP
) == 0) {
203 rtfree(rt
); rt
= rt0
;
204 lookup
: rt
->rt_gwroute
= rtalloc1(rt
->rt_gateway
, 1);
205 if ((rt
= rt
->rt_gwroute
) == 0)
206 senderr(EHOSTUNREACH
);
207 /* the "G" test below also prevents rt == rt0 */
208 if ((rt
->rt_flags
& RTF_GATEWAY
) ||
209 (rt
->rt_ifp
!= ifp
)) {
212 senderr(EHOSTUNREACH
);
216 if (rt
->rt_flags
& RTF_REJECT
)
217 if (rt
->rt_rmx
.rmx_expire
== 0 ||
218 time_second
< rt
->rt_rmx
.rmx_expire
)
219 senderr(rt
== rt0
? EHOSTDOWN
: EHOSTUNREACH
);
222 * If the queueing discipline needs packet classification,
223 * do it before prepending link headers.
225 IFQ_CLASSIFY(&ifp
->if_snd
, m
, dst
->sa_family
, &pktattr
);
228 retry_delay
= hz
/ 16;
230 switch (dst
->sa_family
) {
233 if (m
->m_flags
& M_BCAST
)
234 memcpy(ehdr
.eco_dhost
, eco_broadcastaddr
,
237 else if (!arpresolve(ifp
, rt
, m
, dst
, ehdr
.eco_dhost
))
238 return (0); /* if not yet resolved */
239 /* If broadcasting on a simplex interface, loopback a copy */
240 if ((m
->m_flags
& M_BCAST
) && (ifp
->if_flags
& IFF_SIMPLEX
))
241 mcopy
= m_copy(m
, 0, (int)M_COPYALL
);
242 ehdr
.eco_port
= ECO_PORT_IP
;
243 ehdr
.eco_control
= ECO_CTL_IP
;
247 ah
= mtod(m
, struct arphdr
*);
249 if (ntohs(ah
->ar_pro
) != ETHERTYPE_IP
)
251 ehdr
.eco_port
= ECO_PORT_IP
;
252 switch (ntohs(ah
->ar_op
)) {
254 ehdr
.eco_control
= ECO_CTL_ARP_REQUEST
;
257 ehdr
.eco_control
= ECO_CTL_ARP_REPLY
;
263 if (m
->m_flags
& M_BCAST
)
264 memcpy(ehdr
.eco_dhost
, eco_broadcastaddr
,
270 memcpy(ehdr
.eco_dhost
, tha
, ECO_ADDR_LEN
);
273 MGETHDR(m1
, M_DONTWAIT
, MT_DATA
);
276 M_MOVE_PKTHDR(m1
, m
);
277 m1
->m_len
= sizeof(*ecah
);
278 m1
->m_pkthdr
.len
= m1
->m_len
;
279 MH_ALIGN(m1
, m1
->m_len
);
280 ecah
= mtod(m1
, struct eco_arp
*);
281 memset(ecah
, 0, m1
->m_len
);
282 memcpy(ecah
->ecar_spa
, ar_spa(ah
), ah
->ar_pln
);
283 memcpy(ecah
->ecar_tpa
, ar_tpa(ah
), ah
->ar_pln
);
288 case pseudo_AF_HDRCMPLT
:
292 ehdr
= *(struct eco_header
const *)dst
->sa_data
;
295 log(LOG_ERR
, "%s: can't handle af%d\n", ifp
->if_xname
,
297 senderr(EAFNOSUPPORT
);
301 (void) looutput(ifp
, mcopy
, dst
, rt
);
304 * Add local net header. If no space in first mbuf,
307 M_PREPEND(m
, sizeof (struct eco_header
), M_DONTWAIT
);
310 eh
= mtod(m
, struct eco_header
*);
313 memcpy(eh
->eco_shost
, CLLADDR(ifp
->if_sadl
),
316 if ((m
->m_flags
& M_BCAST
) == 0) {
317 /* Attach retry info to packet. */
318 mtag
= m_tag_get(PACKET_TAG_ECO_RETRYPARMS
,
319 sizeof(struct eco_retryparms
), M_NOWAIT
);
322 erp
= (struct eco_retryparms
*)(mtag
+ 1);
323 erp
->erp_delay
= retry_delay
;
324 erp
->erp_count
= retry_count
;
328 if ((error
= pfil_run_hooks(&ifp
->if_pfil
, &m
, ifp
, PFIL_OUT
)) != 0)
334 return ifq_enqueue(ifp
, m ALTQ_COMMA
ALTQ_DECL(&pktattr
));
343 * Given a scout, decide if we want the rest of the packet.
346 eco_interestingp(struct ifnet
*ifp
, struct mbuf
*m
)
348 struct eco_header
*eh
;
350 eh
= mtod(m
, struct eco_header
*);
351 switch (eh
->eco_port
) {
361 eco_input(struct ifnet
*ifp
, struct mbuf
*m
)
364 struct eco_header ehdr
, *eh
;
368 struct eco_arp
*ecah
;
374 if (pfil_run_hooks(&ifp
->if_pfil
, &m
, ifp
, PFIL_IN
) != 0)
380 /* Copy the mbuf header and trim it off. */
381 /* XXX use m_split? */
383 m_copydata(m
, 0, ECO_HDR_LEN
, (void *)eh
);
384 m_adj(m
, ECO_HDR_LEN
);
386 switch (eh
->eco_port
) {
389 switch (eh
->eco_control
) {
391 schednetisr(NETISR_IP
);
394 case ECO_CTL_ARP_REQUEST
:
395 case ECO_CTL_ARP_REPLY
:
397 * ARP over Econet is strange, because Econet only
398 * supports 8 bytes of data in a broadcast packet.
399 * To cope with this, only the source and destination
400 * IP addresses are actually contained in the packet
401 * and we have to infer the rest and build a fake ARP
402 * packet to pass upwards.
404 if (m
->m_pkthdr
.len
!= sizeof(struct eco_arp
))
406 if (m
->m_len
< sizeof(struct eco_arp
)) {
407 m
= m_pullup(m
, sizeof(struct eco_arp
));
408 if (m
== NULL
) goto drop
;
410 ecah
= mtod(m
, struct eco_arp
*);
411 /* This code derived from arprequest() */
412 MGETHDR(m1
, M_DONTWAIT
, MT_DATA
);
415 M_MOVE_PKTHDR(m1
, m
);
416 m1
->m_len
= sizeof(*ah
) + 2*sizeof(struct in_addr
) +
417 2*ifp
->if_data
.ifi_addrlen
;
418 m1
->m_pkthdr
.len
= m1
->m_len
;
419 MH_ALIGN(m1
, m1
->m_len
);
420 ah
= mtod(m1
, struct arphdr
*);
421 memset((void *)ah
, 0, m1
->m_len
);
422 ah
->ar_pro
= htons(ETHERTYPE_IP
);
423 ah
->ar_hln
= ifp
->if_data
.ifi_addrlen
;
424 ah
->ar_pln
= sizeof(struct in_addr
);
425 if (eh
->eco_control
== ECO_CTL_ARP_REQUEST
)
426 ah
->ar_op
= htons(ARPOP_REQUEST
);
428 ah
->ar_op
= htons(ARPOP_REPLY
);
430 KASSERT(tha
!= NULL
);
431 memcpy(ar_sha(ah
), eh
->eco_shost
, ah
->ar_hln
);
432 memcpy(tha
, eh
->eco_dhost
, ah
->ar_hln
);
433 memcpy(ar_spa(ah
), ecah
->ecar_spa
, ah
->ar_pln
);
434 memcpy(ar_tpa(ah
), ecah
->ecar_tpa
, ah
->ar_pln
);
437 schednetisr(NETISR_ARP
);
440 case ECO_CTL_IPBCAST_REQUEST
:
442 struct sockaddr_storage dst_store
;
443 struct sockaddr
*dst
= (struct sockaddr
*)&dst_store
;
446 memcpy(eh
->eco_dhost
, eh
->eco_shost
, ECO_ADDR_LEN
);
447 eh
->eco_control
= ECO_CTL_IPBCAST_REPLY
;
449 dst
->sa_family
= AF_UNSPEC
;
450 memcpy(dst
->sa_data
, eh
, ECO_HDR_LEN
);
451 ifp
->if_output(ifp
, m
, dst
, NULL
);
455 printf("%s: unknown IP stn %s ctl 0x%02x len %d:",
456 ifp
->if_xname
, eco_sprintf(eh
->eco_shost
),
457 eh
->eco_control
, m
->m_pkthdr
.len
);
465 for (i
= 0; i
< m
->m_len
; i
++)
466 printf(" %02x", mtod(m
, uint8_t *)[i
]);
473 printf("%s: unknown port stn %s port 0x%02x ctl 0x%02x\n",
474 ifp
->if_xname
, eco_sprintf(eh
->eco_shost
),
475 eh
->eco_port
, eh
->eco_control
);
491 eco_start(struct ifnet
*ifp
)
493 struct ecocom
*ec
= (void *)ifp
;
495 struct eco_header
*eh
;
497 if (ec
->ec_state
!= ECO_IDLE
) return;
498 IFQ_DEQUEUE(&ifp
->if_snd
, m
);
499 if (m
== NULL
) return;
500 if (ec
->ec_claimwire(ifp
) == 0) {
501 eh
= mtod(m
, struct eco_header
*);
502 if (eh
->eco_port
== ECO_PORT_IMMEDIATE
) {
503 ec
->ec_txframe(ifp
, m
);
504 ec
->ec_state
= ECO_IMMED_SENT
;
505 } else if (eh
->eco_dhost
[0] == 255) {
506 ec
->ec_txframe(ifp
, m
);
507 ec
->ec_state
= ECO_DONE
;
510 m
= m_copym(m
, 0, ECO_HDR_LEN
, M_DONTWAIT
);
512 m_freem(ec
->ec_packet
);
513 ec
->ec_packet
= NULL
;
516 ec
->ec_txframe(ifp
, m
);
517 ec
->ec_state
= ECO_SCOUT_SENT
;
519 ifp
->if_flags
|= IFF_OACTIVE
;
521 log(LOG_ERR
, "%s: line jammed\n", ifp
->if_xname
);
527 eco_ioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
529 struct ifaddr
*ifa
= (struct ifaddr
*)data
;
534 ifp
->if_flags
|= IFF_UP
;
535 if ((ifp
->if_flags
& IFF_RUNNING
) == 0 &&
536 (error
= (*ifp
->if_init
)(ifp
)) != 0)
538 switch (ifa
->ifa_addr
->sa_family
) {
541 arp_ifinit(ifp
, ifa
);
549 if ((error
= ifioctl_common(ifp
, cmd
, data
)) != ENETRESET
)
551 else if (ifp
->if_flags
& IFF_UP
)
552 return (*ifp
->if_init
)(ifp
);
557 if ((error
= ifioctl_common(ifp
, cmd
, data
)) != 0)
559 switch (ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) {
562 * If interface is marked down and it is running,
563 * then stop and disable it.
565 (*ifp
->if_stop
)(ifp
, 1);
569 * If interface is marked up and it is stopped, then
572 return (*ifp
->if_init
)(ifp
);
573 case IFF_UP
|IFF_RUNNING
:
575 * Reset the interface to pick up changes in any other
576 * flags that affect the hardware state.
578 return (*ifp
->if_init
)(ifp
);
584 return ifioctl_common(ifp
, cmd
, data
);
591 * Handle a raw Econet frame off the interface. The interface may be
592 * flag-filling for a response.
594 * May be called from IPL_NET or IPL_SOFTNET.
598 eco_inputframe(struct ifnet
*ifp
, struct mbuf
*m
)
600 struct ecocom
*ec
= (void *)ifp
;
601 struct eco_header
*eh
, *eh0
;
606 eh
= mtod(m
, struct eco_header
*);
607 switch (ec
->ec_state
) {
608 case ECO_IDLE
: /* Start of a packet (bcast, immed, scout) */
609 if (m
->m_pkthdr
.len
< ECO_HDR_LEN
) {
610 log(LOG_NOTICE
, "%s: undersize scout\n",
614 if (memcmp(eh
->eco_dhost
, eco_broadcastaddr
,
615 ECO_ADDR_LEN
) == 0) {
618 } else if (memcmp(eh
->eco_dhost
, CLLADDR(ifp
->if_sadl
),
619 ECO_ADDR_LEN
) == 0) {
621 if (eh
->eco_port
== ECO_PORT_IMMEDIATE
)
622 return eco_immediate(ifp
, m
);
624 if (eco_interestingp(ifp
, m
)) {
625 reply
= eco_ack(ifp
, m
);
630 ec
->ec_state
= ECO_SCOUT_RCVD
;
639 /* Not for us. Throw it away. */
642 case ECO_SCOUT_RCVD
: /* Packet data */
643 KASSERT(ec
->ec_scout
!= NULL
);
645 eh0
= mtod(m0
, struct eco_header
*);
646 if (m
->m_pkthdr
.len
< ECO_SHDR_LEN
||
647 memcmp(eh
->eco_shost
, eh0
->eco_shost
, ECO_ADDR_LEN
) != 0 ||
648 memcmp(eh
->eco_dhost
, eh0
->eco_dhost
, ECO_ADDR_LEN
) != 0) {
649 log(LOG_NOTICE
, "%s: garbled data packet header\n",
653 reply
= eco_ack(ifp
, m
);
655 * Chop off the small header from this frame, and put
656 * the scout (which holds the control byte and port)
660 m_adj(m
, ECO_SHDR_LEN
);
661 len
= m0
->m_pkthdr
.len
+ m
->m_pkthdr
.len
;
663 m0
->m_pkthdr
.len
= len
;
664 ec
->ec_state
= ECO_DONE
;
667 case ECO_SCOUT_SENT
: /* Scout ack */
668 KASSERT(ec
->ec_packet
!= NULL
);
670 eh0
= mtod(m0
, struct eco_header
*);
671 if (m
->m_pkthdr
.len
!= ECO_SHDR_LEN
||
672 memcmp(eh
->eco_shost
, eh0
->eco_dhost
, ECO_ADDR_LEN
) != 0 ||
673 memcmp(eh
->eco_dhost
, eh0
->eco_shost
, ECO_ADDR_LEN
) != 0) {
674 log(LOG_NOTICE
, "%s: garbled scout ack\n",
679 /* Chop out the control and port bytes. */
680 m0
= m_copym(ec
->ec_packet
, 0, ECO_SHDR_LEN
, M_DONTWAIT
);
682 m_freem(ec
->ec_packet
);
686 ec
->ec_packet
= m_copypacket(m
, M_DONTWAIT
);
687 if (ec
->ec_packet
== NULL
) {
692 m_adj(m
, ECO_HDR_LEN
);
693 len
= m0
->m_pkthdr
.len
+ m
->m_pkthdr
.len
;
694 m_cat(m0
, m
); /* Doesn't update packet header */
695 m0
->m_pkthdr
.len
= len
;
696 ec
->ec_state
= ECO_DATA_SENT
;
698 case ECO_DATA_SENT
: /* Data ack */
699 KASSERT(ec
->ec_packet
!= NULL
);
701 eh0
= mtod(m0
, struct eco_header
*);
702 if (m
->m_pkthdr
.len
!= ECO_SHDR_LEN
||
703 memcmp(eh
->eco_shost
, eh0
->eco_dhost
, ECO_ADDR_LEN
) != 0 ||
704 memcmp(eh
->eco_dhost
, eh0
->eco_shost
, ECO_ADDR_LEN
) != 0) {
705 log(LOG_NOTICE
, "%s: garbled data ack\n",
710 m_freem(ec
->ec_packet
);
711 ec
->ec_packet
= NULL
;
712 ec
->ec_state
= ECO_DONE
;
723 * Handle an immediate operation, and return the reply, or NULL not to reply.
724 * Frees the incoming mbuf.
728 eco_immediate(struct ifnet
*ifp
, struct mbuf
*m
)
730 struct eco_header
*eh
, *reh
;
732 static const uint8_t machinepeek_data
[] = { 42, 0, 0, 1 };
734 eh
= mtod(m
, struct eco_header
*);
735 switch (eh
->eco_control
) {
736 case ECO_CTL_MACHINEPEEK
:
737 MGETHDR(n
, M_DONTWAIT
, MT_DATA
);
740 n
->m_len
= n
->m_pkthdr
.len
= ECO_SHDR_LEN
+ 4;
741 reh
= mtod(n
, struct eco_header
*);
742 memcpy(reh
->eco_dhost
, eh
->eco_shost
,
744 memcpy(reh
->eco_shost
, CLLADDR(ifp
->if_sadl
),
746 memcpy(mtod(n
, char *) + ECO_SHDR_LEN
, machinepeek_data
,
747 sizeof(machinepeek_data
));
758 * Generate (and return) an acknowledgement for a frame. Doesn't free the
759 * original frame, since it's probably needed elsewhere.
762 eco_ack(struct ifnet
*ifp
, struct mbuf
*m
)
764 struct eco_header
*eh
, *reh
;
767 eh
= mtod(m
, struct eco_header
*);
768 MGETHDR(n
, M_DONTWAIT
, MT_DATA
);
771 n
->m_len
= n
->m_pkthdr
.len
= ECO_SHDR_LEN
;
772 reh
= mtod(n
, struct eco_header
*);
773 memcpy(reh
->eco_dhost
, eh
->eco_shost
, ECO_ADDR_LEN
);
774 memcpy(reh
->eco_shost
, CLLADDR(ifp
->if_sadl
), ECO_ADDR_LEN
);
779 eco_inputidle(struct ifnet
*ifp
)
781 struct ecocom
*ec
= (void *)ifp
;
784 struct eco_retryparms
*erp
;
786 switch (ec
->ec_state
) {
790 /* Outgoing packet failed. Check if we should retry. */
792 ec
->ec_packet
= NULL
;
793 mtag
= m_tag_find(m
, PACKET_TAG_ECO_RETRYPARMS
, NULL
);
797 erp
= (struct eco_retryparms
*)(mtag
+ 1);
798 if (--erp
->erp_count
> 0)
799 eco_defer(ifp
, m
, erp
->erp_delay
);
801 printf("%s: pkt failed\n", ifp
->if_xname
);
805 m_freem(ec
->ec_scout
);
811 ec
->ec_state
= ECO_IDLE
;
816 * Convert Econet address to printable (loggable) representation.
819 eco_sprintf(const uint8_t *ea
)
824 snprintf(buf
, sizeof(buf
), "%d", ea
[0]);
826 snprintf(buf
, sizeof(buf
), "%d.%d", ea
[1], ea
[0]);
831 * Econet retry handling.
834 eco_defer(struct ifnet
*ifp
, struct mbuf
*m
, int retry_delay
)
836 struct ecocom
*ec
= (struct ecocom
*)ifp
;
837 struct eco_retry
*er
;
840 er
= malloc(sizeof(*er
), M_TEMP
, M_NOWAIT
);
845 callout_init(&er
->er_callout
, 0);
849 LIST_INSERT_HEAD(&ec
->ec_retries
, er
, er_link
);
851 callout_reset(&er
->er_callout
, retry_delay
, eco_retry
, er
);
855 eco_retry_free(struct eco_retry
*er
)
859 callout_stop(&er
->er_callout
);
860 m_freem(er
->er_packet
);
862 LIST_REMOVE(er
, er_link
);
864 callout_destroy(&er
->er_callout
);
871 struct eco_retry
*er
= arg
;
877 LIST_REMOVE(er
, er_link
);
878 (void)ifq_enqueue(ifp
, m ALTQ_COMMA
ALTQ_DECL(NULL
));