1*f9fd253cSriastradh /* $NetBSD: ddp_input.c,v 1.34 2023/03/30 11:21:08 riastradh Exp $ */
25bf5cd24Schristos
35bf5cd24Schristos /*
45bf5cd24Schristos * Copyright (c) 1990,1994 Regents of The University of Michigan.
55bf5cd24Schristos * All Rights Reserved.
65bf5cd24Schristos *
75bf5cd24Schristos * Permission to use, copy, modify, and distribute this software and
85bf5cd24Schristos * its documentation for any purpose and without fee is hereby granted,
95bf5cd24Schristos * provided that the above copyright notice appears in all copies and
105bf5cd24Schristos * that both that copyright notice and this permission notice appear
115bf5cd24Schristos * in supporting documentation, and that the name of The University
125bf5cd24Schristos * of Michigan not be used in advertising or publicity pertaining to
135bf5cd24Schristos * distribution of the software without specific, written prior
145bf5cd24Schristos * permission. This software is supplied as is without expressed or
155bf5cd24Schristos * implied warranties of any kind.
165bf5cd24Schristos *
175bf5cd24Schristos * This product includes software developed by the University of
185bf5cd24Schristos * California, Berkeley and its contributors.
195bf5cd24Schristos *
205bf5cd24Schristos * Research Systems Unix Group
215bf5cd24Schristos * The University of Michigan
225bf5cd24Schristos * c/o Wesley Craig
235bf5cd24Schristos * 535 W. William Street
245bf5cd24Schristos * Ann Arbor, Michigan
255bf5cd24Schristos * +1-313-764-2278
265bf5cd24Schristos * netatalk@umich.edu
275bf5cd24Schristos */
285bf5cd24Schristos
29b60687cbSlukem #include <sys/cdefs.h>
30*f9fd253cSriastradh __KERNEL_RCSID(0, "$NetBSD: ddp_input.c,v 1.34 2023/03/30 11:21:08 riastradh Exp $");
316f874b81Srjs #include "opt_atalk.h"
32b60687cbSlukem
335bf5cd24Schristos #include <sys/param.h>
345bf5cd24Schristos #include <sys/systm.h>
355bf5cd24Schristos #include <sys/kernel.h>
365bf5cd24Schristos #include <sys/mbuf.h>
375bf5cd24Schristos #include <sys/socket.h>
385bf5cd24Schristos #include <sys/socketvar.h>
395bf5cd24Schristos #include <sys/syslog.h>
405bf5cd24Schristos #include <net/if.h>
415bf5cd24Schristos #include <net/route.h>
425bf5cd24Schristos #include <net/if_ether.h>
435bf5cd24Schristos #include <netinet/in.h>
445bf5cd24Schristos
455bf5cd24Schristos #include <netatalk/at.h>
465bf5cd24Schristos #include <netatalk/at_var.h>
475bf5cd24Schristos #include <netatalk/ddp.h>
485bf5cd24Schristos #include <netatalk/ddp_var.h>
49d2d99542Sthorpej #include <netatalk/ddp_private.h>
505bf5cd24Schristos #include <netatalk/at_extern.h>
515bf5cd24Schristos
525bf5cd24Schristos int ddp_forward = 1;
535bf5cd24Schristos int ddp_firewall = 0;
545bf5cd24Schristos extern int ddp_cksum;
556bd159b8Sthorpej void ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int);
565bf5cd24Schristos
576bd159b8Sthorpej static struct at_ifaddr *
at_ifaddr_for_ifp(struct ifnet * const ifp,int phase_flag)586bd159b8Sthorpej at_ifaddr_for_ifp(struct ifnet * const ifp, int phase_flag)
595bf5cd24Schristos {
605bf5cd24Schristos struct at_ifaddr *aa;
615bf5cd24Schristos
626bd159b8Sthorpej TAILQ_FOREACH(aa, &at_ifaddr, aa_list) {
636bd159b8Sthorpej if (aa->aa_ifp == ifp &&
646bd159b8Sthorpej (aa->aa_flags & AFA_PHASE2) == phase_flag) {
656bd159b8Sthorpej return aa;
666bd159b8Sthorpej }
676bd159b8Sthorpej }
686bd159b8Sthorpej return NULL;
696bd159b8Sthorpej }
705bf5cd24Schristos
716bd159b8Sthorpej void
atintr2(void * arg __unused)726bd159b8Sthorpej atintr2(void *arg __unused)
736bd159b8Sthorpej {
746bd159b8Sthorpej struct mbuf *m;
756bd159b8Sthorpej
766bd159b8Sthorpej mutex_enter(softnet_lock);
776bd159b8Sthorpej while ((m = pktq_dequeue(at_pktq2)) != NULL) {
786bd159b8Sthorpej struct ifnet *ifp;
790f46b890Smatt
805249b5a2Sjonathan m_claimm(m, &atalk_rx_mowner);
81fe6d4275Sozaki-r ifp = m_get_rcvif_NOMPSAFE(m);
826bd159b8Sthorpej if (at_ifaddr_for_ifp(ifp, AFA_PHASE2) == NULL) {
836bd159b8Sthorpej /* ifp not an appletalk interface */
845bf5cd24Schristos m_freem(m);
855bf5cd24Schristos continue;
865bf5cd24Schristos }
877f3d4048Splunky ddp_input(m, ifp, NULL, 2);
885bf5cd24Schristos }
896bd159b8Sthorpej mutex_exit(softnet_lock);
906bd159b8Sthorpej }
915bf5cd24Schristos
926bd159b8Sthorpej void
atintr1(void * arg __unused)936bd159b8Sthorpej atintr1(void *arg __unused)
946bd159b8Sthorpej {
956bd159b8Sthorpej struct mbuf *m;
965bf5cd24Schristos
976bd159b8Sthorpej mutex_enter(softnet_lock);
986bd159b8Sthorpej while ((m = pktq_dequeue(at_pktq1)) != NULL) {
996bd159b8Sthorpej struct ifnet *ifp;
1006bd159b8Sthorpej struct elaphdr *elhp, elh;
1010f46b890Smatt
1025249b5a2Sjonathan m_claimm(m, &atalk_rx_mowner);
103fe6d4275Sozaki-r ifp = m_get_rcvif_NOMPSAFE(m);
1046bd159b8Sthorpej if (at_ifaddr_for_ifp(ifp, 0) == NULL) {
1056bd159b8Sthorpej /* ifp not an appletalk interface */
1065bf5cd24Schristos m_freem(m);
1075bf5cd24Schristos continue;
1085bf5cd24Schristos }
1095bf5cd24Schristos if (m->m_len < SZ_ELAPHDR &&
1105bf5cd24Schristos ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) {
111d2d99542Sthorpej DDP_STATINC(DDP_STAT_TOOSHORT);
1125bf5cd24Schristos continue;
1135bf5cd24Schristos }
1145bf5cd24Schristos elhp = mtod(m, struct elaphdr *);
1155bf5cd24Schristos m_adj(m, SZ_ELAPHDR);
1165bf5cd24Schristos
1175bf5cd24Schristos if (elhp->el_type == ELAP_DDPEXTEND) {
1187f3d4048Splunky ddp_input(m, ifp, NULL, 1);
1195bf5cd24Schristos } else {
120e2cb8590Scegger memcpy((void *) & elh, (void *) elhp, SZ_ELAPHDR);
1215bf5cd24Schristos ddp_input(m, ifp, &elh, 1);
1225bf5cd24Schristos }
1235bf5cd24Schristos }
12415e29e98Sad mutex_exit(softnet_lock);
1255bf5cd24Schristos }
1265bf5cd24Schristos
1275bf5cd24Schristos struct route forwro;
1285bf5cd24Schristos
1295bf5cd24Schristos void
ddp_input(struct mbuf * m,struct ifnet * ifp,struct elaphdr * elh,int phase)130454af1c0Sdsl ddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase)
1315bf5cd24Schristos {
13272fa642aSdyoung struct rtentry *rt;
1335bf5cd24Schristos struct sockaddr_at from, to;
1345bf5cd24Schristos struct ddpshdr *dsh, ddps;
1355bf5cd24Schristos struct at_ifaddr *aa;
1365bf5cd24Schristos struct ddpehdr *deh = NULL, ddpe;
1375bf5cd24Schristos struct ddpcb *ddp;
1385bf5cd24Schristos int dlen, mlen;
1395bf5cd24Schristos u_short cksum = 0;
14072f0a6dfSdyoung union {
14172f0a6dfSdyoung struct sockaddr dst;
14272f0a6dfSdyoung struct sockaddr_at dsta;
14372f0a6dfSdyoung } u;
1445bf5cd24Schristos
145c363a9cbScegger memset((void *) & from, 0, sizeof(struct sockaddr_at));
1465bf5cd24Schristos if (elh) {
147d2d99542Sthorpej DDP_STATINC(DDP_STAT_SHORT);
1485bf5cd24Schristos
1495bf5cd24Schristos if (m->m_len < sizeof(struct ddpshdr) &&
1505bf5cd24Schristos ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) {
151d2d99542Sthorpej DDP_STATINC(DDP_STAT_TOOSHORT);
1525bf5cd24Schristos return;
1535bf5cd24Schristos }
1545bf5cd24Schristos dsh = mtod(m, struct ddpshdr *);
155e2cb8590Scegger memcpy((void *) & ddps, (void *) dsh, sizeof(struct ddpshdr));
1565bf5cd24Schristos ddps.dsh_bytes = ntohl(ddps.dsh_bytes);
1575bf5cd24Schristos dlen = ddps.dsh_len;
1585bf5cd24Schristos
1595bf5cd24Schristos to.sat_addr.s_net = ATADDR_ANYNET;
1605bf5cd24Schristos to.sat_addr.s_node = elh->el_dnode;
1615bf5cd24Schristos to.sat_port = ddps.dsh_dport;
1625bf5cd24Schristos from.sat_addr.s_net = ATADDR_ANYNET;
1635bf5cd24Schristos from.sat_addr.s_node = elh->el_snode;
1645bf5cd24Schristos from.sat_port = ddps.dsh_sport;
1655bf5cd24Schristos
166*f9fd253cSriastradh TAILQ_FOREACH(aa, &at_ifaddr, aa_list) {
1675bf5cd24Schristos if (aa->aa_ifp == ifp &&
1685bf5cd24Schristos (aa->aa_flags & AFA_PHASE2) == 0 &&
1695bf5cd24Schristos (AA_SAT(aa)->sat_addr.s_node ==
1705bf5cd24Schristos to.sat_addr.s_node ||
1715bf5cd24Schristos to.sat_addr.s_node == ATADDR_BCAST))
1725bf5cd24Schristos break;
1735bf5cd24Schristos }
1745bf5cd24Schristos if (aa == NULL) {
1755bf5cd24Schristos m_freem(m);
1765bf5cd24Schristos return;
1775bf5cd24Schristos }
1785bf5cd24Schristos } else {
179d2d99542Sthorpej DDP_STATINC(DDP_STAT_LONG);
1805bf5cd24Schristos
1815bf5cd24Schristos if (m->m_len < sizeof(struct ddpehdr) &&
1825bf5cd24Schristos ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) {
183d2d99542Sthorpej DDP_STATINC(DDP_STAT_TOOSHORT);
1845bf5cd24Schristos return;
1855bf5cd24Schristos }
1865bf5cd24Schristos deh = mtod(m, struct ddpehdr *);
187e2cb8590Scegger memcpy((void *) & ddpe, (void *) deh, sizeof(struct ddpehdr));
1885bf5cd24Schristos ddpe.deh_bytes = ntohl(ddpe.deh_bytes);
1895bf5cd24Schristos dlen = ddpe.deh_len;
1905bf5cd24Schristos
1915bf5cd24Schristos if ((cksum = ddpe.deh_sum) == 0) {
192d2d99542Sthorpej DDP_STATINC(DDP_STAT_NOSUM);
1935bf5cd24Schristos }
1945bf5cd24Schristos from.sat_addr.s_net = ddpe.deh_snet;
1955bf5cd24Schristos from.sat_addr.s_node = ddpe.deh_snode;
1965bf5cd24Schristos from.sat_port = ddpe.deh_sport;
1975bf5cd24Schristos to.sat_addr.s_net = ddpe.deh_dnet;
1985bf5cd24Schristos to.sat_addr.s_node = ddpe.deh_dnode;
1995bf5cd24Schristos to.sat_port = ddpe.deh_dport;
2005bf5cd24Schristos
2015bf5cd24Schristos if (to.sat_addr.s_net == ATADDR_ANYNET) {
202*f9fd253cSriastradh TAILQ_FOREACH(aa, &at_ifaddr, aa_list) {
2035bf5cd24Schristos if (phase == 1 && (aa->aa_flags & AFA_PHASE2))
2045bf5cd24Schristos continue;
2055bf5cd24Schristos
2065bf5cd24Schristos if (phase == 2 &&
2075bf5cd24Schristos (aa->aa_flags & AFA_PHASE2) == 0)
2085bf5cd24Schristos continue;
2095bf5cd24Schristos
2105bf5cd24Schristos if (aa->aa_ifp == ifp &&
2115bf5cd24Schristos (AA_SAT(aa)->sat_addr.s_node ==
2125bf5cd24Schristos to.sat_addr.s_node ||
2135bf5cd24Schristos to.sat_addr.s_node == ATADDR_BCAST ||
2145bf5cd24Schristos (ifp->if_flags & IFF_LOOPBACK)))
2155bf5cd24Schristos break;
2165bf5cd24Schristos }
2175bf5cd24Schristos } else {
218*f9fd253cSriastradh TAILQ_FOREACH(aa, &at_ifaddr, aa_list) {
2195bf5cd24Schristos if (to.sat_addr.s_net == aa->aa_firstnet &&
2205bf5cd24Schristos to.sat_addr.s_node == 0)
2215bf5cd24Schristos break;
2225bf5cd24Schristos
2235bf5cd24Schristos if ((ntohs(to.sat_addr.s_net) <
2245bf5cd24Schristos ntohs(aa->aa_firstnet) ||
2255bf5cd24Schristos ntohs(to.sat_addr.s_net) >
2265bf5cd24Schristos ntohs(aa->aa_lastnet)) &&
2279e4ad708Swrstuden (ntohs(to.sat_addr.s_net) < 0xff00 ||
2289e4ad708Swrstuden ntohs(to.sat_addr.s_net) > 0xfffe))
2295bf5cd24Schristos continue;
2305bf5cd24Schristos
2315bf5cd24Schristos if (to.sat_addr.s_node !=
2325bf5cd24Schristos AA_SAT(aa)->sat_addr.s_node &&
2335bf5cd24Schristos to.sat_addr.s_node != ATADDR_BCAST)
2345bf5cd24Schristos continue;
2355bf5cd24Schristos
2365bf5cd24Schristos break;
2375bf5cd24Schristos }
2385bf5cd24Schristos }
2395bf5cd24Schristos }
2405bf5cd24Schristos
2415bf5cd24Schristos /*
2425bf5cd24Schristos * Adjust the length, removing any padding that may have been added
2435bf5cd24Schristos * at a link layer. We do this before we attempt to forward a packet,
2445bf5cd24Schristos * possibly on a different media.
2455bf5cd24Schristos */
2465bf5cd24Schristos mlen = m->m_pkthdr.len;
2475bf5cd24Schristos if (mlen < dlen) {
248d2d99542Sthorpej DDP_STATINC(DDP_STAT_TOOSMALL);
2495bf5cd24Schristos m_freem(m);
2505bf5cd24Schristos return;
2515bf5cd24Schristos }
2525bf5cd24Schristos if (mlen > dlen) {
2535bf5cd24Schristos m_adj(m, dlen - mlen);
2545bf5cd24Schristos }
2555bf5cd24Schristos /*
2565bf5cd24Schristos * XXX Should we deliver broadcasts locally, also, or rely on the
2575bf5cd24Schristos * link layer to give us a copy? For the moment, the latter.
2585bf5cd24Schristos */
2595bf5cd24Schristos if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST &&
2605bf5cd24Schristos aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) {
2615bf5cd24Schristos if (ddp_forward == 0) {
2625bf5cd24Schristos m_freem(m);
2635bf5cd24Schristos return;
2645bf5cd24Schristos }
26572f0a6dfSdyoung sockaddr_at_init(&u.dsta, &to.sat_addr, 0);
266833d4399Sdyoung rt = rtcache_lookup(&forwro, &u.dst);
26772f0a6dfSdyoung #if 0 /* XXX The if-condition is always false. What was this
26872f0a6dfSdyoung * actually trying to test?
26972f0a6dfSdyoung */
2705bf5cd24Schristos if (to.sat_addr.s_net !=
2715493f188Sdyoung satocsat(rtcache_getdst(&forwro))->sat_addr.s_net &&
2725bf5cd24Schristos ddpe.deh_hops == DDP_MAXHOPS) {
2735bf5cd24Schristos m_freem(m);
2745bf5cd24Schristos return;
2755bf5cd24Schristos }
27672f0a6dfSdyoung #endif
277833d4399Sdyoung if (ddp_firewall && (rt == NULL || rt->rt_ifp != ifp)) {
2784c25fb2fSozaki-r rtcache_unref(rt, &forwro);
2795bf5cd24Schristos m_freem(m);
2805bf5cd24Schristos return;
2815bf5cd24Schristos }
2824c25fb2fSozaki-r rtcache_unref(rt, &forwro);
2835bf5cd24Schristos ddpe.deh_hops++;
2845bf5cd24Schristos ddpe.deh_bytes = htonl(ddpe.deh_bytes);
285e2cb8590Scegger memcpy((void *) deh, (void *) & ddpe, sizeof(u_short));/*XXX*/
2865bf5cd24Schristos if (ddp_route(m, &forwro)) {
287d2d99542Sthorpej DDP_STATINC(DDP_STAT_CANTFORWARD);
2885bf5cd24Schristos } else {
289d2d99542Sthorpej DDP_STATINC(DDP_STAT_FORWARD);
2905bf5cd24Schristos }
2915bf5cd24Schristos return;
2925bf5cd24Schristos }
2935bf5cd24Schristos from.sat_len = sizeof(struct sockaddr_at);
2945bf5cd24Schristos from.sat_family = AF_APPLETALK;
2955bf5cd24Schristos
2965bf5cd24Schristos if (elh) {
2975bf5cd24Schristos m_adj(m, sizeof(struct ddpshdr));
2985bf5cd24Schristos } else {
2995bf5cd24Schristos if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) {
300d2d99542Sthorpej DDP_STATINC(DDP_STAT_BADSUM);
3015bf5cd24Schristos m_freem(m);
3025bf5cd24Schristos return;
3035bf5cd24Schristos }
3045bf5cd24Schristos m_adj(m, sizeof(struct ddpehdr));
3055bf5cd24Schristos }
3065bf5cd24Schristos
3075bf5cd24Schristos if ((ddp = ddp_search(&from, &to, aa)) == NULL) {
3085bf5cd24Schristos m_freem(m);
3095bf5cd24Schristos return;
3105bf5cd24Schristos }
3115bf5cd24Schristos if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from,
3125bf5cd24Schristos m, (struct mbuf *) 0) == 0) {
313d2d99542Sthorpej DDP_STATINC(DDP_STAT_NOSOCKSPACE);
31438d01a8dSroy soroverflow(ddp->ddp_socket);
3155bf5cd24Schristos m_freem(m);
3165bf5cd24Schristos return;
3175bf5cd24Schristos }
318da1b3a7aSaidan #if IFA_STATS
319da1b3a7aSaidan if (aa)
320da1b3a7aSaidan aa->aa_ifa.ifa_data.ifad_inbytes += dlen;
321da1b3a7aSaidan #endif
3225bf5cd24Schristos sorwakeup(ddp->ddp_socket);
3235bf5cd24Schristos }
3245bf5cd24Schristos
3255bf5cd24Schristos #if 0
3265bf5cd24Schristos
3275bf5cd24Schristos #define BPXLEN 48
3285bf5cd24Schristos #define BPALEN 16
3295bf5cd24Schristos #include <ctype.h>
3305bf5cd24Schristos
3315bf5cd24Schristos static void
332454af1c0Sdsl bprint(char *data, int len)
3335bf5cd24Schristos {
3345bf5cd24Schristos char xout[BPXLEN], aout[BPALEN];
3355bf5cd24Schristos int i = 0;
3365bf5cd24Schristos
337c363a9cbScegger memset(xout, 0, BPXLEN);
338c363a9cbScegger memset(aout, 0, BPALEN);
3395bf5cd24Schristos
3405bf5cd24Schristos for (;;) {
3415bf5cd24Schristos if (len < 1) {
3425bf5cd24Schristos if (i != 0) {
3435bf5cd24Schristos printf("%s\t%s\n", xout, aout);
3445bf5cd24Schristos }
3455bf5cd24Schristos printf("%s\n", "(end)");
3465bf5cd24Schristos break;
3475bf5cd24Schristos }
348362a4a0bSchristos xout[(i * 3)] = hexdigits[(*data & 0xf0) >> 4];
349362a4a0bSchristos xout[(i * 3) + 1] = hexdigits[*data & 0x0f];
3505bf5cd24Schristos
3515bf5cd24Schristos if ((u_char) * data < 0x7f && (u_char) * data > 0x20) {
3525bf5cd24Schristos aout[i] = *data;
3535bf5cd24Schristos } else {
3545bf5cd24Schristos aout[i] = '.';
3555bf5cd24Schristos }
3565bf5cd24Schristos
3575bf5cd24Schristos xout[(i * 3) + 2] = ' ';
3585bf5cd24Schristos
3595bf5cd24Schristos i++;
3605bf5cd24Schristos len--;
3615bf5cd24Schristos data++;
3625bf5cd24Schristos
3635bf5cd24Schristos if (i > BPALEN - 2) {
3645bf5cd24Schristos printf("%s\t%s\n", xout, aout);
365c363a9cbScegger memset(xout, 0, BPXLEN);
366c363a9cbScegger memset(aout, 0, BPALEN);
3675bf5cd24Schristos i = 0;
3685bf5cd24Schristos continue;
3695bf5cd24Schristos }
3705bf5cd24Schristos }
3715bf5cd24Schristos }
3725bf5cd24Schristos
3735bf5cd24Schristos static void
374454af1c0Sdsl m_printm(struct mbuf *m)
3755bf5cd24Schristos {
3765bf5cd24Schristos for (; m; m = m->m_next)
3775bf5cd24Schristos bprint(mtod(m, char *), m->m_len);
3785bf5cd24Schristos }
3795bf5cd24Schristos #endif
380