FreeBSD/Linux Kernel Cross Reference
sys/net/if_ecosubr.c
1 /* $NetBSD: if_ecosubr.c,v 1.13 2003/08/07 16:32:51 agc Exp $ */
2
3 /*-
4 * Copyright (c) 2001 Ben Harris
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
17 *
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.
28 */
29 /*
30 * Copyright (c) 1982, 1989, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
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.
44 *
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
55 * SUCH DAMAGE.
56 *
57 * @(#)if_ethersubr.c 8.2 (Berkeley) 4/4/96
58 */
59
60 #include <sys/cdefs.h>
61 __KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.13 2003/08/07 16:32:51 agc Exp $");
62
63 #include "bpfilter.h"
64 #include "opt_inet.h"
65 #include "opt_pfil_hooks.h"
66
67 #include <sys/param.h>
68
69 __KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.13 2003/08/07 16:32:51 agc Exp $");
70
71 #include <sys/errno.h>
72 #include <sys/kernel.h>
73 #include <sys/socket.h>
74 #include <sys/sockio.h>
75 #include <sys/syslog.h>
76 #include <sys/systm.h>
77
78 #include <net/if.h>
79 #include <net/if_dl.h>
80 #include <net/if_eco.h>
81 #include <net/if_types.h>
82 #include <net/netisr.h>
83 #include <net/route.h>
84
85 #if NBPFILTER > 0
86 #include <net/bpf.h>
87 #endif
88
89 #ifdef INET
90 #include <net/ethertypes.h>
91 #include <net/if_arp.h>
92 #include <netinet/in.h>
93 #include <netinet/in_var.h>
94 #endif
95
96 #define ECO_MAUX_RETRYPARMS 0
97
98 struct eco_retryparms {
99 int erp_delay;
100 int erp_count;
101 };
102
103 /* Default broadcast address */
104 static const u_int8_t eco_broadcastaddr[] = { 0xff, 0xff };
105
106 static int eco_output(struct ifnet *, struct mbuf *, struct sockaddr *,
107 struct rtentry *);
108 static void eco_input(struct ifnet *, struct mbuf *);
109 static void eco_start(struct ifnet *);
110 static int eco_ioctl(struct ifnet *, u_long, caddr_t);
111
112 static int eco_interestingp(struct ifnet *ifp, struct mbuf *m);
113 static struct mbuf *eco_immediate(struct ifnet *ifp, struct mbuf *m);
114 static struct mbuf *eco_ack(struct ifnet *ifp, struct mbuf *m);
115
116 static void eco_defer(struct ifnet *, struct mbuf *, int);
117 static void eco_retry_free(struct eco_retry *er);
118 static void eco_retry(void *);
119
120 void
121 eco_ifattach(struct ifnet *ifp, const u_int8_t *lla)
122 {
123 struct ecocom *ec = (void *)ifp;
124
125 ifp->if_type = IFT_ECONET;
126 ifp->if_addrlen = ECO_ADDR_LEN;
127 ifp->if_hdrlen = ECO_HDR_LEN;
128 ifp->if_dlt = DLT_ECONET;
129 ifp->if_mtu = ECO_MTU;
130
131 ifp->if_output = eco_output;
132 ifp->if_input = eco_input;
133 ifp->if_start = eco_start;
134 ifp->if_ioctl = eco_ioctl;
135
136 /* ifp->if_baudrate...; */
137 if_alloc_sadl(ifp);
138 memcpy(LLADDR(ifp->if_sadl), lla, ifp->if_addrlen);
139
140 /* XXX cast safe? */
141 ifp->if_broadcastaddr = (u_int8_t *)eco_broadcastaddr;
142
143 LIST_INIT(&ec->ec_retries);
144
145 #if NBPFILTER > 0
146 bpfattach(ifp, ifp->if_dlt, ECO_HDR_LEN);
147 #endif
148 }
149
150 #define senderr(e) do { \
151 error = (e); \
152 goto bad; \
153 } while (/*CONSTCOND*/0)
154
155 int
156 eco_init(struct ifnet *ifp) {
157 struct ecocom *ec = (struct ecocom *)ifp;
158
159 if ((ifp->if_flags & IFF_RUNNING) == 0)
160 ec->ec_state = ECO_UNKNOWN;
161 return 0;
162 }
163
164 void
165 eco_stop(struct ifnet *ifp, int disable)
166 {
167 struct ecocom *ec = (struct ecocom *)ifp;
168
169 while (!LIST_EMPTY(&ec->ec_retries))
170 eco_retry_free(LIST_FIRST(&ec->ec_retries));
171 }
172
173 static int
174 eco_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
175 struct rtentry *rt0)
176 {
177 struct eco_header ehdr, *eh;
178 int error, s;
179 struct mbuf *m = m0, *mcopy = NULL;
180 struct rtentry *rt;
181 int hdrcmplt;
182 size_t len;
183 int delay, count;
184 struct m_tag *mtag;
185 struct eco_retryparms *erp;
186 #ifdef INET
187 struct mbuf *m1;
188 struct arphdr *ah;
189 struct eco_arp *ecah;
190 #endif
191 ALTQ_DECL(struct altq_pktattr pktattr;)
192
193 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
194 senderr(ENETDOWN);
195 if ((rt = rt0) != NULL) {
196 if ((rt->rt_flags & RTF_UP) == 0) {
197 if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
198 rt->rt_refcnt--;
199 if (rt->rt_ifp != ifp)
200 return (*rt->rt_ifp->if_output)
201 (ifp, m0, dst, rt);
202 } else
203 senderr(EHOSTUNREACH);
204 }
205 if ((rt->rt_flags & RTF_GATEWAY) && dst->sa_family != AF_NS) {
206 if (rt->rt_gwroute == 0)
207 goto lookup;
208 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
209 rtfree(rt); rt = rt0;
210 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
211 if ((rt = rt->rt_gwroute) == 0)
212 senderr(EHOSTUNREACH);
213 /* the "G" test below also prevents rt == rt0 */
214 if ((rt->rt_flags & RTF_GATEWAY) ||
215 (rt->rt_ifp != ifp)) {
216 rt->rt_refcnt--;
217 rt0->rt_gwroute = 0;
218 senderr(EHOSTUNREACH);
219 }
220 }
221 }
222 if (rt->rt_flags & RTF_REJECT)
223 if (rt->rt_rmx.rmx_expire == 0 ||
224 time.tv_sec < rt->rt_rmx.rmx_expire)
225 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
226 }
227 /*
228 * If the queueing discipline needs packet classification,
229 * do it before prepending link headers.
230 */
231 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
232
233 hdrcmplt = 0;
234 delay = hz / 16;
235 count = 16;
236 switch (dst->sa_family) {
237 #ifdef INET
238 case AF_INET:
239 if (m->m_flags & M_BCAST)
240 memcpy(ehdr.eco_dhost, eco_broadcastaddr,
241 ECO_ADDR_LEN);
242
243 else if (!arpresolve(ifp, rt, m, dst, ehdr.eco_dhost))
244 return (0); /* if not yet resolved */
245 /* If broadcasting on a simplex interface, loopback a copy */
246 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
247 mcopy = m_copy(m, 0, (int)M_COPYALL);
248 ehdr.eco_port = ECO_PORT_IP;
249 ehdr.eco_control = ECO_CTL_IP;
250 break;
251
252 case AF_ARP:
253 ah = mtod(m, struct arphdr *);
254
255 if (ntohs(ah->ar_pro) != ETHERTYPE_IP)
256 return EAFNOSUPPORT;
257 ehdr.eco_port = ECO_PORT_IP;
258 switch (ntohs(ah->ar_op)) {
259 case ARPOP_REQUEST:
260 ehdr.eco_control = ECO_CTL_ARP_REQUEST;
261 break;
262 case ARPOP_REPLY:
263 ehdr.eco_control = ECO_CTL_ARP_REPLY;
264 break;
265 default:
266 return EOPNOTSUPP;
267 }
268
269 if (m->m_flags & M_BCAST)
270 memcpy(ehdr.eco_dhost, eco_broadcastaddr,
271 ECO_ADDR_LEN);
272 else
273 memcpy(ehdr.eco_dhost, ar_tha(ah), ECO_ADDR_LEN);
274
275 MGETHDR(m1, M_DONTWAIT, MT_DATA);
276 if (m1 == NULL)
277 senderr(ENOBUFS);
278 M_COPY_PKTHDR(m1, m);
279 m1->m_len = sizeof(*ecah);
280 m1->m_pkthdr.len = m1->m_len;
281 MH_ALIGN(m1, m1->m_len);
282 ecah = mtod(m1, struct eco_arp *);
283 memset(ecah, 0, m1->m_len);
284 memcpy(ecah->ecar_spa, ar_spa(ah), ah->ar_pln);
285 memcpy(ecah->ecar_tpa, ar_tpa(ah), ah->ar_pln);
286 m_freem(m);
287 m = m1;
288 break;
289 #endif
290 case pseudo_AF_HDRCMPLT:
291 hdrcmplt = 1;
292 /* FALLTHROUGH */
293 case AF_UNSPEC:
294 eh = (struct eco_header *)dst->sa_data;
295 ehdr = *eh;
296 break;
297 default:
298 log(LOG_ERR, "%s: can't handle af%d\n", ifp->if_xname,
299 dst->sa_family);
300 senderr(EAFNOSUPPORT);
301 }
302
303 if (mcopy)
304 (void) looutput(ifp, mcopy, dst, rt);
305
306 /*
307 * Add local net header. If no space in first mbuf,
308 * allocate another.
309 */
310 M_PREPEND(m, sizeof (struct eco_header), M_DONTWAIT);
311 if (m == 0)
312 senderr(ENOBUFS);
313 eh = mtod(m, struct eco_header *);
314 *eh = ehdr;
315 if (!hdrcmplt)
316 memcpy(eh->eco_shost, LLADDR(ifp->if_sadl),
317 ECO_ADDR_LEN);
318
319 if ((m->m_flags & M_BCAST) == 0) {
320 /* Attach retry info to packet. */
321 mtag = m_tag_get(PACKET_TAG_ECO_RETRYPARMS,
322 sizeof(struct eco_retryparms), M_NOWAIT);
323 if (mtag == NULL)
324 senderr(ENOBUFS);
325 erp = (struct eco_retryparms *)(mtag + 1);
326 erp->erp_delay = delay;
327 erp->erp_count = count;
328 }
329
330 #ifdef PFIL_HOOKS
331 if ((error = pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_OUT)) != 0)
332 return (error);
333 if (m == NULL)
334 return (0);
335 #endif
336
337 /*
338 * Queue message on interface, and start output if interface
339 * not yet active.
340 */
341
342 len = m->m_pkthdr.len;
343 s = splnet();
344 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
345 if (error) {
346 splx(s);
347 return (error);
348 }
349 ifp->if_obytes += len;
350 if ((ifp->if_flags & IFF_OACTIVE) == 0)
351 (*ifp->if_start)(ifp);
352 splx(s);
353 return (error);
354
355 bad:
356 if (m)
357 m_freem(m);
358 return error;
359 }
360
361 /*
362 * Given a scout, decide if we want the rest of the packet.
363 */
364 static int
365 eco_interestingp(struct ifnet *ifp, struct mbuf *m)
366 {
367 struct eco_header *eh;
368
369 eh = mtod(m, struct eco_header *);
370 switch (eh->eco_port) {
371 #ifdef INET
372 case ECO_PORT_IP:
373 return 1;
374 #endif
375 }
376 return 0;
377 }
378
379 static void
380 eco_input(struct ifnet *ifp, struct mbuf *m)
381 {
382 struct ifqueue *inq;
383 struct eco_header ehdr, *eh;
384 int s, i;
385 #ifdef INET
386 struct arphdr *ah;
387 struct eco_arp *ecah;
388 struct mbuf *m1;
389 #endif
390
391 #ifdef PFIL_HOOKS
392 if (pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_IN) != 0)
393 return;
394 if (m == NULL)
395 return;
396 #endif
397
398 /* Copy the mbuf header and trim it off. */
399 /* XXX use m_split? */
400 eh = &ehdr;
401 m_copydata(m, 0, ECO_HDR_LEN, (caddr_t)eh);
402 m_adj(m, ECO_HDR_LEN);
403
404 switch (eh->eco_port) {
405 #ifdef INET
406 case ECO_PORT_IP:
407 switch (eh->eco_control) {
408 case ECO_CTL_IP:
409 schednetisr(NETISR_IP);
410 inq = &ipintrq;
411 break;
412 case ECO_CTL_ARP_REQUEST:
413 case ECO_CTL_ARP_REPLY:
414 /*
415 * ARP over Econet is strange, because Econet only
416 * supports 8 bytes of data in a broadcast packet.
417 * To cope with this, only the source and destination
418 * IP addresses are actually contained in the packet
419 * and we have to infer the rest and build a fake ARP
420 * packet to pass upwards.
421 */
422 if (m->m_pkthdr.len != sizeof(struct eco_arp))
423 goto drop;
424 if (m->m_len < sizeof(struct eco_arp)) {
425 m = m_pullup(m, sizeof(struct eco_arp));
426 if (m == NULL) goto drop;
427 }
428 ecah = mtod(m, struct eco_arp *);
429 /* This code derived from arprequest() */
430 MGETHDR(m1, M_DONTWAIT, MT_DATA);
431 if (m1 == NULL)
432 goto drop;
433 M_COPY_PKTHDR(m1, m);
434 m1->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
435 2*ifp->if_data.ifi_addrlen;
436 m1->m_pkthdr.len = m1->m_len;
437 MH_ALIGN(m1, m1->m_len);
438 ah = mtod(m1, struct arphdr *);
439 bzero((caddr_t)ah, m1->m_len);
440 ah->ar_pro = htons(ETHERTYPE_IP);
441 ah->ar_hln = ifp->if_data.ifi_addrlen;
442 ah->ar_pln = sizeof(struct in_addr);
443 if (eh->eco_control == ECO_CTL_ARP_REQUEST)
444 ah->ar_op = htons(ARPOP_REQUEST);
445 else
446 ah->ar_op = htons(ARPOP_REPLY);
447 memcpy(ar_sha(ah), eh->eco_shost, ah->ar_hln);
448 memcpy(ar_tha(ah), eh->eco_dhost, ah->ar_hln);
449 memcpy(ar_spa(ah), ecah->ecar_spa, ah->ar_pln);
450 memcpy(ar_tpa(ah), ecah->ecar_tpa, ah->ar_pln);
451 m_freem(m);
452 m = m1;
453 schednetisr(NETISR_ARP);
454 inq = &arpintrq;
455 break;
456 case ECO_CTL_IPBCAST_REQUEST:
457 {
458 struct sockaddr_storage dst_store;
459 struct sockaddr *dst = (struct sockaddr *)&dst_store;
460
461 /* Queue? */
462 memcpy(eh->eco_dhost, eh->eco_shost, ECO_ADDR_LEN);
463 eh->eco_control = ECO_CTL_IPBCAST_REPLY;
464 /* dst->sa_len??? */
465 dst->sa_family = AF_UNSPEC;
466 memcpy(dst->sa_data, eh, ECO_HDR_LEN);
467 ifp->if_output(ifp, m, dst, NULL);
468 return;
469 }
470 default:
471 printf("%s: unknown IP stn %s ctl 0x%02x len %d:",
472 ifp->if_xname, eco_sprintf(eh->eco_shost),
473 eh->eco_control, m->m_pkthdr.len);
474 if (m->m_len == 0) {
475 m = m_pullup(m, 1);
476 if (m == 0) {
477 printf("\n");
478 goto drop;
479 }
480 }
481 for (i = 0; i < m->m_len; i++)
482 printf(" %02x", mtod(m, u_int8_t *)[i]);
483 printf("\n");
484 goto drop;
485 }
486 break;
487 #endif
488 default:
489 printf("%s: unknown port stn %s port 0x%02x ctl 0x%02x\n",
490 ifp->if_xname, eco_sprintf(eh->eco_shost),
491 eh->eco_port, eh->eco_control);
492 drop:
493 m_freem(m);
494 return;
495 }
496
497 s = splnet();
498 if (IF_QFULL(inq)) {
499 IF_DROP(inq);
500 m_freem(m);
501 } else
502 IF_ENQUEUE(inq, m);
503 splx(s);
504 }
505
506 static void
507 eco_start(struct ifnet *ifp)
508 {
509 struct ecocom *ec = (void *)ifp;
510 struct mbuf *m;
511 struct eco_header *eh;
512
513 if (ec->ec_state != ECO_IDLE) return;
514 IFQ_DEQUEUE(&ifp->if_snd, m);
515 if (m == NULL) return;
516 if (ec->ec_claimwire(ifp) == 0) {
517 eh = mtod(m, struct eco_header *);
518 if (eh->eco_port == ECO_PORT_IMMEDIATE) {
519 ec->ec_txframe(ifp, m);
520 ec->ec_state = ECO_IMMED_SENT;
521 } else if (eh->eco_dhost[0] == 255) {
522 ec->ec_txframe(ifp, m);
523 ec->ec_state = ECO_DONE;
524 } else {
525 ec->ec_packet = m;
526 m = m_copym(m, 0, ECO_HDR_LEN, M_DONTWAIT);
527 if (m == NULL) {
528 m_freem(ec->ec_packet);
529 ec->ec_packet = NULL;
530 return;
531 }
532 ec->ec_txframe(ifp, m);
533 ec->ec_state = ECO_SCOUT_SENT;
534 }
535 ifp->if_flags |= IFF_OACTIVE;
536 } else {
537 log(LOG_ERR, "%s: line jammed\n", ifp->if_xname);
538 m_freem(m);
539 }
540 }
541
542 static int
543 eco_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
544 {
545 struct ifreq *ifr = (struct ifreq *)data;
546 struct ifaddr *ifa = (struct ifaddr *)data;
547 int error = 0;
548
549 switch (cmd) {
550 case SIOCSIFADDR:
551 ifp->if_flags |= IFF_UP;
552 switch (ifa->ifa_addr->sa_family) {
553 #ifdef INET
554 case AF_INET:
555 if ((ifp->if_flags & IFF_RUNNING) == 0 &&
556 (error = (*ifp->if_init)(ifp)) != 0)
557 break;
558 arp_ifinit(ifp, ifa);
559 break;
560 #endif
561 default:
562 if ((ifp->if_flags & IFF_RUNNING) == 0)
563 error = (*ifp->if_init)(ifp);
564 break;
565 }
566 break;
567 case SIOCSIFMTU:
568 ifp->if_mtu = ifr->ifr_mtu;
569
570 /* Make sure the device notices the MTU change. */
571 if (ifp->if_flags & IFF_UP)
572 error = (*ifp->if_init)(ifp);
573 break;
574 case SIOCSIFFLAGS:
575 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) {
576 /*
577 * If interface is marked down and it is running,
578 * then stop and disable it.
579 */
580 (*ifp->if_stop)(ifp, 1);
581 } else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) {
582 /*
583 * If interface is marked up and it is stopped, then
584 * start it.
585 */
586 error = (*ifp->if_init)(ifp);
587 } else if ((ifp->if_flags & IFF_UP) != 0) {
588 /*
589 * Reset the interface to pick up changes in any other
590 * flags that affect the hardware state.
591 */
592 error = (*ifp->if_init)(ifp);
593 }
594 break;
595 default:
596 error = ENOTTY;
597 }
598
599 return error;
600 }
601
602 /*
603 * Handle a raw Econet frame off the interface. The interface may be
604 * flag-filling for a response.
605 *
606 * May be called from IPL_NET or IPL_SOFTNET.
607 */
608
609 struct mbuf *
610 eco_inputframe(struct ifnet *ifp, struct mbuf *m)
611 {
612 struct ecocom *ec = (void *)ifp;
613 struct eco_header *eh, *eh0;
614 struct mbuf *m0;
615 struct mbuf *reply;
616 int len;
617
618 eh = mtod(m, struct eco_header *);
619 switch (ec->ec_state) {
620 case ECO_IDLE: /* Start of a packet (bcast, immed, scout) */
621 if (m->m_pkthdr.len < ECO_HDR_LEN) {
622 log(LOG_NOTICE, "%s: undersize scout\n",
623 ifp->if_xname);
624 goto drop;
625 }
626 if (memcmp(eh->eco_dhost, eco_broadcastaddr,
627 ECO_ADDR_LEN) == 0) {
628 /* Broadcast */
629 eco_input(ifp, m);
630 } else if (memcmp(eh->eco_dhost, LLADDR(ifp->if_sadl),
631 ECO_ADDR_LEN) == 0) {
632 /* Unicast for us */
633 if (eh->eco_port == ECO_PORT_IMMEDIATE)
634 return eco_immediate(ifp, m);
635 else {
636 if (eco_interestingp(ifp, m)) {
637 reply = eco_ack(ifp, m);
638 if (reply == NULL) {
639 m_freem(m);
640 return NULL;
641 }
642 ec->ec_state = ECO_SCOUT_RCVD;
643 ec->ec_scout = m;
644 return reply;
645 } else {
646 m_freem(m);
647 return NULL;
648 }
649 }
650 } else
651 /* Not for us. Throw it away. */
652 m_freem(m);
653 break;
654 case ECO_SCOUT_RCVD: /* Packet data */
655 KASSERT(ec->ec_scout != NULL);
656 m0 = ec->ec_scout;
657 eh0 = mtod(m0, struct eco_header *);
658 if (m->m_pkthdr.len < ECO_SHDR_LEN ||
659 memcmp(eh->eco_shost, eh0->eco_shost, ECO_ADDR_LEN) != 0 ||
660 memcmp(eh->eco_dhost, eh0->eco_dhost, ECO_ADDR_LEN) != 0) {
661 log(LOG_NOTICE, "%s: garbled data packet header\n",
662 ifp->if_xname);
663 goto drop;
664 }
665 reply = eco_ack(ifp, m);
666 /*
667 * Chop off the small header from this frame, and put
668 * the scout (which holds the control byte and port)
669 * in its place.
670 */
671 ec->ec_scout = NULL;
672 m_adj(m, ECO_SHDR_LEN);
673 len = m0->m_pkthdr.len + m->m_pkthdr.len;
674 m_cat(m0, m);
675 m0->m_pkthdr.len = len;
676 ec->ec_state = ECO_DONE;
677 eco_input(ifp, m0);
678 return reply;
679 case ECO_SCOUT_SENT: /* Scout ack */
680 KASSERT(ec->ec_packet != NULL);
681 m0 = ec->ec_packet;
682 eh0 = mtod(m0, struct eco_header *);
683 if (m->m_pkthdr.len != ECO_SHDR_LEN ||
684 memcmp(eh->eco_shost, eh0->eco_dhost, ECO_ADDR_LEN) != 0 ||
685 memcmp(eh->eco_dhost, eh0->eco_shost, ECO_ADDR_LEN) != 0) {
686 log(LOG_NOTICE, "%s: garbled scout ack\n",
687 ifp->if_xname);
688 goto drop;
689 }
690 m_freem(m);
691 /* Chop out the control and port bytes. */
692 m0 = m_copym(ec->ec_packet, 0, ECO_SHDR_LEN, M_DONTWAIT);
693 if (m0 == NULL) {
694 m_freem(ec->ec_packet);
695 return NULL;
696 }
697 m = ec->ec_packet;
698 ec->ec_packet = m_copypacket(m, M_DONTWAIT);
699 if (ec->ec_packet == NULL) {
700 m_freem(m0);
701 m_freem(m);
702 return NULL;
703 }
704 m_adj(m, ECO_HDR_LEN);
705 len = m0->m_pkthdr.len + m->m_pkthdr.len;
706 m_cat(m0, m); /* Doesn't update packet header */
707 m0->m_pkthdr.len = len;
708 ec->ec_state = ECO_DATA_SENT;
709 return m0;
710 case ECO_DATA_SENT: /* Data ack */
711 KASSERT(ec->ec_packet != NULL);
712 m0 = ec->ec_packet;
713 eh0 = mtod(m0, struct eco_header *);
714 if (m->m_pkthdr.len != ECO_SHDR_LEN ||
715 memcmp(eh->eco_shost, eh0->eco_dhost, ECO_ADDR_LEN) != 0 ||
716 memcmp(eh->eco_dhost, eh0->eco_shost, ECO_ADDR_LEN) != 0) {
717 log(LOG_NOTICE, "%s: garbled data ack\n",
718 ifp->if_xname);
719 goto drop;
720 }
721 m_freem(m);
722 m_freem(ec->ec_packet);
723 ec->ec_packet = NULL;
724 ec->ec_state = ECO_DONE;
725 return NULL;
726 default:
727 drop:
728 m_freem(m);
729 break;
730 }
731 return NULL;
732 }
733
734 /*
735 * Handle an immediate operation, and return the reply, or NULL not to reply.
736 * Frees the incoming mbuf.
737 */
738
739 static struct mbuf *
740 eco_immediate(struct ifnet *ifp, struct mbuf *m)
741 {
742 struct eco_header *eh, *reh;
743 struct mbuf *n;
744 static const u_int8_t machinepeek_data[] = { 42, 0, 0, 1 };
745
746 eh = mtod(m, struct eco_header *);
747 switch (eh->eco_control) {
748 case ECO_CTL_MACHINEPEEK:
749 MGETHDR(n, M_DONTWAIT, MT_DATA);
750 if (n == NULL)
751 goto bad;
752 n->m_len = n->m_pkthdr.len = ECO_SHDR_LEN + 4;
753 reh = mtod(n, struct eco_header *);
754 memcpy(reh->eco_dhost, eh->eco_shost,
755 ECO_ADDR_LEN);
756 memcpy(reh->eco_shost, LLADDR(ifp->if_sadl),
757 ECO_ADDR_LEN);
758 memcpy(mtod(n, caddr_t) + ECO_SHDR_LEN, machinepeek_data,
759 sizeof(machinepeek_data));
760 m_freem(m);
761 return n;
762 default:
763 bad:
764 m_freem(m);
765 return NULL;
766 }
767 }
768
769 /*
770 * Generate (and return) an acknowledgement for a frame. Doesn't free the
771 * original frame, since it's probably needed elsewhere.
772 */
773 static struct mbuf *
774 eco_ack(struct ifnet *ifp, struct mbuf *m)
775 {
776 struct eco_header *eh, *reh;
777 struct mbuf *n;
778
779 eh = mtod(m, struct eco_header *);
780 MGETHDR(n, M_DONTWAIT, MT_DATA);
781 if (n == NULL)
782 return NULL;
783 n->m_len = n->m_pkthdr.len = ECO_SHDR_LEN;
784 reh = mtod(n, struct eco_header *);
785 memcpy(reh->eco_dhost, eh->eco_shost, ECO_ADDR_LEN);
786 memcpy(reh->eco_shost, LLADDR(ifp->if_sadl), ECO_ADDR_LEN);
787 return n;
788 }
789
790 void
791 eco_inputidle(struct ifnet *ifp)
792 {
793 struct ecocom *ec = (void *)ifp;
794 struct mbuf *m;
795 struct m_tag *mtag;
796 struct eco_retryparms *erp;
797
798 switch (ec->ec_state) {
799 case ECO_SCOUT_SENT:
800 case ECO_DATA_SENT:
801 case ECO_IMMED_SENT:
802 /* Outgoing packet failed. Check if we should retry. */
803 m = ec->ec_packet;
804 ec->ec_packet = NULL;
805 mtag = m_tag_find(m, PACKET_TAG_ECO_RETRYPARMS, NULL);
806 if (mtag == NULL)
807 m_freem(m);
808 else {
809 erp = (struct eco_retryparms *)(mtag + 1);
810 if (--erp->erp_count > 0)
811 eco_defer(ifp, m, erp->erp_delay);
812 else
813 printf("%s: pkt failed\n", ifp->if_xname);
814 }
815 break;
816 case ECO_SCOUT_RCVD:
817 m_freem(ec->ec_scout);
818 ec->ec_scout = NULL;
819 break;
820 default:
821 break;
822 }
823 ec->ec_state = ECO_IDLE;
824 ifp->if_start(ifp);
825 }
826
827 /*
828 * Convert Econet address to printable (loggable) representation.
829 */
830 char *
831 eco_sprintf(const u_int8_t *ea)
832 {
833 static char buf[8];
834
835 if (ea[1] == 0)
836 sprintf(buf, "%d", ea[0]);
837 else
838 sprintf(buf, "%d.%d", ea[1], ea[0]);
839 return buf;
840 }
841
842 /*
843 * Econet retry handling.
844 */
845 static void
846 eco_defer(struct ifnet *ifp, struct mbuf *m, int delay)
847 {
848 struct ecocom *ec = (struct ecocom *)ifp;
849 struct eco_retry *er;
850 int s;
851
852 MALLOC(er, struct eco_retry *, sizeof(*er), M_TEMP, M_NOWAIT);
853 if (er == NULL) {
854 m_freem(m);
855 return;
856 }
857 callout_init(&er->er_callout);
858 er->er_packet = m;
859 er->er_ifp = ifp;
860 s = splnet();
861 LIST_INSERT_HEAD(&ec->ec_retries, er, er_link);
862 splx(s);
863 callout_reset(&er->er_callout, delay, eco_retry, er);
864 }
865
866 static void
867 eco_retry_free(struct eco_retry *er)
868 {
869 int s;
870
871 callout_stop(&er->er_callout);
872 m_freem(er->er_packet);
873 s = splnet();
874 LIST_REMOVE(er, er_link);
875 splx(s);
876 FREE(er, M_TEMP);
877 }
878
879 static void
880 eco_retry(void *arg)
881 {
882 struct eco_retry *er = arg;
883 struct mbuf *m;
884 struct ifnet *ifp;
885 int s, error, len;
886
887 ifp = er->er_ifp;
888 m = er->er_packet;
889 len = m->m_pkthdr.len;
890 LIST_REMOVE(er, er_link);
891 s = splnet();
892 IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
893 if (error) {
894 splx(s);
895 /* XXX should defer again? */
896 m_freem(m);
897 }
898 ifp->if_obytes += len;
899 if ((ifp->if_flags & IFF_OACTIVE) == 0)
900 (*ifp->if_start)(ifp);
901 splx(s);
902 FREE(er, M_TEMP);
903 }
Cache object: 683aa3c6fae5361b2917c57102c32aa8
|