if_arcsubr.c revision 1.66.8.1 1 /* $NetBSD: if_arcsubr.c,v 1.66.8.1 2017/03/13 07:41:27 skrll Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995 Ignatios Souvatzis
5 * Copyright (c) 1982, 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
33 * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
34 *
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: if_arcsubr.c,v 1.66.8.1 2017/03/13 07:41:27 skrll Exp $");
39
40 #include "opt_inet.h"
41
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/mbuf.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/ioctl.h>
51 #include <sys/errno.h>
52 #include <sys/syslog.h>
53
54 #include <sys/cpu.h>
55
56 #include <net/if.h>
57 #include <net/netisr.h>
58 #include <net/route.h>
59 #include <net/if_dl.h>
60 #include <net/if_types.h>
61 #include <net/if_arc.h>
62 #include <net/if_arp.h>
63 #include <net/if_ether.h>
64
65 #include <net/bpf.h>
66
67 #ifdef INET
68 #include <netinet/in.h>
69 #include <netinet/in_var.h>
70 #include <netinet/if_inarp.h>
71 #endif
72
73 #ifdef INET6
74 #ifndef INET
75 #include <netinet/in.h>
76 #endif
77 #include <netinet6/in6_var.h>
78 #include <netinet6/nd6.h>
79 #endif
80
81 #define ARCNET_ALLOW_BROKEN_ARP
82
83 #ifndef ARC_IPMTU
84 #define ARC_IPMTU 1500
85 #endif
86
87 static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
88
89 /*
90 * RC1201 requires us to have this configurable. We have it only per
91 * machine at the moment... there is no generic "set mtu" ioctl, AFAICS.
92 * Anyway, it is possible to binpatch this or set it per kernel config
93 * option.
94 */
95 #if ARC_IPMTU > 60480
96 ERROR: The arc_ipmtu is ARC_IPMTU, but must not exceed 60480.
97 #endif
98 int arc_ipmtu = ARC_IPMTU;
99 uint8_t arcbroadcastaddr = 0;
100
101 #define senderr(e) { error = (e); goto bad;}
102
103 static int arc_output(struct ifnet *, struct mbuf *,
104 const struct sockaddr *, struct rtentry *);
105 static void arc_input(struct ifnet *, struct mbuf *);
106
107 /*
108 * ARCnet output routine.
109 * Encapsulate a packet of type family for the local net.
110 * Assumes that ifp is actually pointer to arccom structure.
111 */
112 static int
113 arc_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
114 struct rtentry *rt0)
115 {
116 struct mbuf *m, *m1, *mcopy;
117 struct rtentry *rt;
118 struct arccom *ac;
119 const struct arc_header *cah;
120 struct arc_header *ah;
121 struct arphdr *arph;
122 int error, newencoding;
123 uint8_t atype, adst, myself;
124 int tfrags, sflag, fsflag, rsflag;
125 ALTQ_DECL(struct altq_pktattr pktattr;)
126
127 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
128 return (ENETDOWN); /* m, m1 aren't initialized yet */
129
130 error = newencoding = 0;
131 ac = (struct arccom *)ifp;
132 m = m0;
133 mcopy = m1 = NULL;
134
135 myself = *CLLADDR(ifp->if_sadl);
136
137 if ((rt = rt0)) {
138 if ((rt->rt_flags & RTF_UP) == 0) {
139 if ((rt0 = rt = rtalloc1(dst, 1)))
140 rt->rt_refcnt--;
141 else
142 senderr(EHOSTUNREACH);
143 }
144 if (rt->rt_flags & RTF_GATEWAY) {
145 if (rt->rt_gwroute == 0)
146 goto lookup;
147 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
148 rtfree(rt); rt = rt0;
149 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
150 if ((rt = rt->rt_gwroute) == 0)
151 senderr(EHOSTUNREACH);
152 }
153 }
154 if (rt->rt_flags & RTF_REJECT)
155 if (rt->rt_rmx.rmx_expire == 0 ||
156 time_second < rt->rt_rmx.rmx_expire)
157 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
158 }
159
160 /*
161 * if the queueing discipline needs packet classification,
162 * do it before prepending link headers.
163 */
164 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
165
166 switch (dst->sa_family) {
167 #ifdef INET
168 case AF_INET:
169
170 /*
171 * For now, use the simple IP addr -> ARCnet addr mapping
172 */
173 if (m->m_flags & (M_BCAST|M_MCAST))
174 adst = arcbroadcastaddr; /* ARCnet broadcast address */
175 else if (ifp->if_flags & IFF_NOARP)
176 adst = ntohl(satocsin(dst)->sin_addr.s_addr) & 0xFF;
177 else if (!arpresolve(ifp, rt, m, dst, &adst))
178 return 0; /* not resolved yet */
179
180 /* If broadcasting on a simplex interface, loopback a copy */
181 if ((m->m_flags & (M_BCAST|M_MCAST)) &&
182 (ifp->if_flags & IFF_SIMPLEX))
183 mcopy = m_copy(m, 0, (int)M_COPYALL);
184 if (ifp->if_flags & IFF_LINK0) {
185 atype = ARCTYPE_IP;
186 newencoding = 1;
187 } else {
188 atype = ARCTYPE_IP_OLD;
189 newencoding = 0;
190 }
191 break;
192
193 case AF_ARP:
194 arph = mtod(m, struct arphdr *);
195 if (m->m_flags & M_BCAST)
196 adst = arcbroadcastaddr;
197 else {
198 uint8_t *tha = ar_tha(arph);
199 if (tha == NULL) {
200 m_freem(m);
201 return 0;
202 }
203 adst = *tha;
204 }
205
206 arph->ar_hrd = htons(ARPHRD_ARCNET);
207
208 switch (ntohs(arph->ar_op)) {
209 case ARPOP_REVREQUEST:
210 case ARPOP_REVREPLY:
211 if (!(ifp->if_flags & IFF_LINK0)) {
212 printf("%s: can't handle af%d\n",
213 ifp->if_xname, dst->sa_family);
214 senderr(EAFNOSUPPORT);
215 }
216
217 atype = htons(ARCTYPE_REVARP);
218 newencoding = 1;
219 break;
220
221 case ARPOP_REQUEST:
222 case ARPOP_REPLY:
223 default:
224 if (ifp->if_flags & IFF_LINK0) {
225 atype = htons(ARCTYPE_ARP);
226 newencoding = 1;
227 } else {
228 atype = htons(ARCTYPE_ARP_OLD);
229 newencoding = 0;
230 }
231 }
232 #ifdef ARCNET_ALLOW_BROKEN_ARP
233 /*
234 * XXX It's not clear per RFC826 if this is needed, but
235 * "assigned numbers" say this is wrong.
236 * However, e.g., AmiTCP 3.0Beta used it... we make this
237 * switchable for emergency cases. Not perfect, but...
238 */
239 if (ifp->if_flags & IFF_LINK2)
240 arph->ar_pro = atype - 1;
241 #endif
242 break;
243 #endif
244 #ifdef INET6
245 case AF_INET6:
246 if (!nd6_storelladdr(ifp, rt, m, dst, &adst, sizeof(adst)))
247 return (0); /* it must be impossible, but... */
248 atype = htons(ARCTYPE_INET6);
249 newencoding = 1;
250 break;
251 #endif
252
253 case AF_UNSPEC:
254 cah = (const struct arc_header *)dst->sa_data;
255 adst = cah->arc_dhost;
256 atype = cah->arc_type;
257 break;
258
259 default:
260 printf("%s: can't handle af%d\n", ifp->if_xname,
261 dst->sa_family);
262 senderr(EAFNOSUPPORT);
263 }
264
265 if (mcopy)
266 (void) looutput(ifp, mcopy, dst, rt);
267
268 /*
269 * Add local net header. If no space in first mbuf,
270 * allocate another.
271 *
272 * For ARCnet, this is just symbolic. The header changes
273 * form and position on its way into the hardware and out of
274 * the wire. At this point, it contains source, destination and
275 * packet type.
276 */
277 if (newencoding) {
278 ++ac->ac_seqid; /* make the seqid unique */
279
280 tfrags = (m->m_pkthdr.len + 503) / 504;
281 fsflag = 2 * tfrags - 3;
282 sflag = 0;
283 rsflag = fsflag;
284
285 while (sflag < fsflag) {
286 /* we CAN'T have short packets here */
287 m1 = m_split(m, 504, M_DONTWAIT);
288 if (m1 == 0)
289 senderr(ENOBUFS);
290
291 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
292 if (m == 0)
293 senderr(ENOBUFS);
294 ah = mtod(m, struct arc_header *);
295 ah->arc_type = atype;
296 ah->arc_dhost = adst;
297 ah->arc_shost = myself;
298 ah->arc_flag = rsflag;
299 ah->arc_seqid = ac->ac_seqid;
300
301 if ((error = ifq_enqueue(ifp, m ALTQ_COMMA
302 ALTQ_DECL(&pktattr))) != 0)
303 return (error);
304
305 m = m1;
306 sflag += 2;
307 rsflag = sflag;
308 }
309 m1 = NULL;
310
311
312 /* here we can have small, especially forbidden packets */
313
314 if ((m->m_pkthdr.len >=
315 ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
316 (m->m_pkthdr.len <=
317 ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
318
319 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT);
320 if (m == 0)
321 senderr(ENOBUFS);
322 ah = mtod(m, struct arc_header *);
323 ah->arc_flag = 0xFF;
324 ah->arc_seqid = 0xFFFF;
325 ah->arc_type2 = atype;
326 ah->arc_flag2 = sflag;
327 ah->arc_seqid2 = ac->ac_seqid;
328 } else {
329 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
330 if (m == 0)
331 senderr(ENOBUFS);
332 ah = mtod(m, struct arc_header *);
333 ah->arc_flag = sflag;
334 ah->arc_seqid = ac->ac_seqid;
335 }
336
337 ah->arc_dhost = adst;
338 ah->arc_shost = myself;
339 ah->arc_type = atype;
340 } else {
341 M_PREPEND(m, ARC_HDRLEN, M_DONTWAIT);
342 if (m == 0)
343 senderr(ENOBUFS);
344 ah = mtod(m, struct arc_header *);
345 ah->arc_type = atype;
346 ah->arc_dhost = adst;
347 ah->arc_shost = myself;
348 }
349
350 return ifq_enqueue(ifp, m ALTQ_COMMA ALTQ_DECL(&pktattr));
351
352 bad:
353 if (m1)
354 m_freem(m1);
355 if (m)
356 m_freem(m);
357 return (error);
358 }
359
360 /*
361 * Defragmenter. Returns mbuf if last packet found, else
362 * NULL. frees imcoming mbuf as necessary.
363 */
364
365 static struct mbuf *
366 arc_defrag(struct ifnet *ifp, struct mbuf *m)
367 {
368 struct arc_header *ah, *ah1;
369 struct arccom *ac;
370 struct ac_frag *af;
371 struct mbuf *m1;
372 const char *s;
373 int newflen;
374 u_char src, dst, typ;
375
376 ac = (struct arccom *)ifp;
377
378 if (m->m_len < ARC_HDRNEWLEN) {
379 m = m_pullup(m, ARC_HDRNEWLEN);
380 if (m == NULL) {
381 ++ifp->if_ierrors;
382 return NULL;
383 }
384 }
385
386 ah = mtod(m, struct arc_header *);
387 typ = ah->arc_type;
388
389 if (!arc_isphds(typ))
390 return m;
391
392 src = ah->arc_shost;
393 dst = ah->arc_dhost;
394
395 if (ah->arc_flag == 0xff) {
396 m_adj(m, 4);
397
398 if (m->m_len < ARC_HDRNEWLEN) {
399 m = m_pullup(m, ARC_HDRNEWLEN);
400 if (m == NULL) {
401 ++ifp->if_ierrors;
402 return NULL;
403 }
404 }
405
406 ah = mtod(m, struct arc_header *);
407 }
408
409 af = &ac->ac_fragtab[src];
410 m1 = af->af_packet;
411 s = "debug code error";
412
413 if (ah->arc_flag & 1) {
414 /*
415 * first fragment. We always initialize, which is
416 * about the right thing to do, as we only want to
417 * accept one fragmented packet per src at a time.
418 */
419 if (m1 != NULL)
420 m_freem(m1);
421
422 af->af_packet = m;
423 m1 = m;
424 af->af_maxflag = ah->arc_flag;
425 af->af_lastseen = 0;
426 af->af_seqid = ah->arc_seqid;
427
428 return NULL;
429 /* notreached */
430 } else {
431 /* check for unfragmented packet */
432 if (ah->arc_flag == 0)
433 return m;
434
435 /* do we have a first packet from that src? */
436 if (m1 == NULL) {
437 s = "no first frag";
438 goto outofseq;
439 }
440
441 ah1 = mtod(m1, struct arc_header *);
442
443 if (ah->arc_seqid != ah1->arc_seqid) {
444 s = "seqid differs";
445 goto outofseq;
446 }
447
448 if (typ != ah1->arc_type) {
449 s = "type differs";
450 goto outofseq;
451 }
452
453 if (dst != ah1->arc_dhost) {
454 s = "dest host differs";
455 goto outofseq;
456 }
457
458 /* typ, seqid and dst are ok here. */
459
460 if (ah->arc_flag == af->af_lastseen) {
461 m_freem(m);
462 return NULL;
463 }
464
465 if (ah->arc_flag == af->af_lastseen + 2) {
466 /* ok, this is next fragment */
467 af->af_lastseen = ah->arc_flag;
468 m_adj(m, ARC_HDRNEWLEN);
469
470 /*
471 * m_cat might free the first mbuf (with pkthdr)
472 * in 2nd chain; therefore:
473 */
474
475 newflen = m->m_pkthdr.len;
476
477 m_cat(m1, m);
478
479 m1->m_pkthdr.len += newflen;
480
481 /* is it the last one? */
482 if (af->af_lastseen > af->af_maxflag) {
483 af->af_packet = NULL;
484 return (m1);
485 } else
486 return NULL;
487 }
488 s = "other reason";
489 /* if all else fails, it is out of sequence, too */
490 }
491 outofseq:
492 if (m1) {
493 m_freem(m1);
494 af->af_packet = NULL;
495 }
496
497 if (m)
498 m_freem(m);
499
500 log(LOG_INFO,"%s: got out of seq. packet: %s\n",
501 ifp->if_xname, s);
502
503 return NULL;
504 }
505
506 /*
507 * return 1 if Packet Header Definition Standard, else 0.
508 * For now: old IP, old ARP aren't obviously. Lacking correct information,
509 * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
510 * (Apple and Novell corporations were involved, among others, in PHDS work).
511 * Easiest is to assume that everybody else uses that, too.
512 */
513 int
514 arc_isphds(uint8_t type)
515 {
516 return (type != ARCTYPE_IP_OLD &&
517 type != ARCTYPE_ARP_OLD &&
518 type != ARCTYPE_DIAGNOSE);
519 }
520
521 /*
522 * Process a received Arcnet packet;
523 * the packet is in the mbuf chain m with
524 * the ARCnet header.
525 */
526 static void
527 arc_input(struct ifnet *ifp, struct mbuf *m)
528 {
529 pktqueue_t *pktq = NULL;
530 struct arc_header *ah;
531 struct ifqueue *inq;
532 uint8_t atype;
533 int isr = 0;
534 int s;
535
536 if ((ifp->if_flags & IFF_UP) == 0) {
537 m_freem(m);
538 return;
539 }
540
541 /* possibly defragment: */
542 m = arc_defrag(ifp, m);
543 if (m == NULL)
544 return;
545
546 ah = mtod(m, struct arc_header *);
547
548 ifp->if_ibytes += m->m_pkthdr.len;
549
550 if (arcbroadcastaddr == ah->arc_dhost) {
551 m->m_flags |= M_BCAST|M_MCAST;
552 ifp->if_imcasts++;
553 }
554
555 atype = ah->arc_type;
556 switch (atype) {
557 #ifdef INET
558 case ARCTYPE_IP:
559 m_adj(m, ARC_HDRNEWLEN);
560 pktq = ip_pktq;
561 break;
562
563 case ARCTYPE_IP_OLD:
564 m_adj(m, ARC_HDRLEN);
565 pktq = ip_pktq;
566 break;
567
568 case ARCTYPE_ARP:
569 m_adj(m, ARC_HDRNEWLEN);
570 isr = NETISR_ARP;
571 inq = &arpintrq;
572 #ifdef ARCNET_ALLOW_BROKEN_ARP
573 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
574 #endif
575 break;
576
577 case ARCTYPE_ARP_OLD:
578 m_adj(m, ARC_HDRLEN);
579 isr = NETISR_ARP;
580 inq = &arpintrq;
581 #ifdef ARCNET_ALLOW_BROKEN_ARP
582 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
583 #endif
584 break;
585 #endif
586 #ifdef INET6
587 case ARCTYPE_INET6:
588 m_adj(m, ARC_HDRNEWLEN);
589 pktq = ip6_pktq;
590 break;
591 #endif
592 default:
593 m_freem(m);
594 return;
595 }
596
597 s = splnet();
598 if (__predict_true(pktq)) {
599 if (__predict_false(!pktq_enqueue(pktq, m, 0))) {
600 m_freem(m);
601 }
602 splx(s);
603 return;
604 }
605 if (IF_QFULL(inq)) {
606 IF_DROP(inq);
607 m_freem(m);
608 } else {
609 IF_ENQUEUE(inq, m);
610 schednetisr(isr);
611 }
612 splx(s);
613 }
614
615 /*
616 * Convert Arcnet address to printable (loggable) representation.
617 */
618 char *
619 arc_sprintf(uint8_t *ap)
620 {
621 static char arcbuf[3];
622 char *cp = arcbuf;
623
624 *cp++ = hexdigits[*ap >> 4];
625 *cp++ = hexdigits[*ap++ & 0xf];
626 *cp = 0;
627 return (arcbuf);
628 }
629
630 /*
631 * Perform common duties while attaching to interface list
632 */
633 void
634 arc_ifattach(struct ifnet *ifp, uint8_t lla)
635 {
636 struct arccom *ac;
637
638 ifp->if_type = IFT_ARCNET;
639 ifp->if_addrlen = 1;
640 ifp->if_hdrlen = ARC_HDRLEN;
641 ifp->if_dlt = DLT_ARCNET;
642 if (ifp->if_flags & IFF_BROADCAST)
643 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
644 if (ifp->if_flags & IFF_LINK0 && arc_ipmtu > ARC_PHDS_MAXMTU)
645 log(LOG_ERR,
646 "%s: arc_ipmtu is %d, but must not exceed %d\n",
647 ifp->if_xname, arc_ipmtu, ARC_PHDS_MAXMTU);
648
649 ifp->if_output = arc_output;
650 ifp->if_input = arc_input;
651 ac = (struct arccom *)ifp;
652 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
653 if (lla == 0) {
654 /* XXX this message isn't entirely clear, to me -- cgd */
655 log(LOG_ERR,"%s: link address 0 reserved for broadcasts. Please change it and ifconfig %s down up\n",
656 ifp->if_xname, ifp->if_xname);
657 }
658 if_attach(ifp);
659 if_set_sadl(ifp, &lla, sizeof(lla), true);
660
661 ifp->if_broadcastaddr = &arcbroadcastaddr;
662
663 bpf_attach(ifp, DLT_ARCNET, ARC_HDRLEN);
664 }
665