1 1.34 riastrad /* $NetBSD: ddp_input.c,v 1.34 2023/03/30 11:21:08 riastradh Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (c) 1990,1994 Regents of The University of Michigan. 5 1.1 christos * All Rights Reserved. 6 1.1 christos * 7 1.1 christos * Permission to use, copy, modify, and distribute this software and 8 1.1 christos * its documentation for any purpose and without fee is hereby granted, 9 1.1 christos * provided that the above copyright notice appears in all copies and 10 1.1 christos * that both that copyright notice and this permission notice appear 11 1.1 christos * in supporting documentation, and that the name of The University 12 1.1 christos * of Michigan not be used in advertising or publicity pertaining to 13 1.1 christos * distribution of the software without specific, written prior 14 1.1 christos * permission. This software is supplied as is without expressed or 15 1.1 christos * implied warranties of any kind. 16 1.1 christos * 17 1.1 christos * This product includes software developed by the University of 18 1.1 christos * California, Berkeley and its contributors. 19 1.1 christos * 20 1.1 christos * Research Systems Unix Group 21 1.1 christos * The University of Michigan 22 1.1 christos * c/o Wesley Craig 23 1.1 christos * 535 W. William Street 24 1.1 christos * Ann Arbor, Michigan 25 1.1 christos * +1-313-764-2278 26 1.1 christos * netatalk (at) umich.edu 27 1.1 christos */ 28 1.6 lukem 29 1.6 lukem #include <sys/cdefs.h> 30 1.34 riastrad __KERNEL_RCSID(0, "$NetBSD: ddp_input.c,v 1.34 2023/03/30 11:21:08 riastradh Exp $"); 31 1.30 rjs #include "opt_atalk.h" 32 1.1 christos 33 1.1 christos #include <sys/param.h> 34 1.1 christos #include <sys/systm.h> 35 1.1 christos #include <sys/kernel.h> 36 1.1 christos #include <sys/mbuf.h> 37 1.1 christos #include <sys/socket.h> 38 1.1 christos #include <sys/socketvar.h> 39 1.1 christos #include <sys/syslog.h> 40 1.1 christos #include <net/if.h> 41 1.1 christos #include <net/route.h> 42 1.1 christos #include <net/if_ether.h> 43 1.1 christos #include <netinet/in.h> 44 1.1 christos 45 1.1 christos #include <netatalk/at.h> 46 1.1 christos #include <netatalk/at_var.h> 47 1.1 christos #include <netatalk/ddp.h> 48 1.1 christos #include <netatalk/ddp_var.h> 49 1.18 thorpej #include <netatalk/ddp_private.h> 50 1.1 christos #include <netatalk/at_extern.h> 51 1.1 christos 52 1.1 christos int ddp_forward = 1; 53 1.1 christos int ddp_firewall = 0; 54 1.1 christos extern int ddp_cksum; 55 1.32 thorpej void ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int); 56 1.32 thorpej 57 1.32 thorpej static struct at_ifaddr * 58 1.32 thorpej at_ifaddr_for_ifp(struct ifnet * const ifp, int phase_flag) 59 1.32 thorpej { 60 1.32 thorpej struct at_ifaddr *aa; 61 1.32 thorpej 62 1.32 thorpej TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 63 1.32 thorpej if (aa->aa_ifp == ifp && 64 1.32 thorpej (aa->aa_flags & AFA_PHASE2) == phase_flag) { 65 1.32 thorpej return aa; 66 1.32 thorpej } 67 1.32 thorpej } 68 1.32 thorpej return NULL; 69 1.32 thorpej } 70 1.1 christos 71 1.1 christos void 72 1.32 thorpej atintr2(void *arg __unused) 73 1.1 christos { 74 1.32 thorpej struct mbuf *m; 75 1.1 christos 76 1.19 ad mutex_enter(softnet_lock); 77 1.32 thorpej while ((m = pktq_dequeue(at_pktq2)) != NULL) { 78 1.32 thorpej struct ifnet *ifp; 79 1.8 matt 80 1.9 jonathan m_claimm(m, &atalk_rx_mowner); 81 1.27 ozaki ifp = m_get_rcvif_NOMPSAFE(m); 82 1.32 thorpej if (at_ifaddr_for_ifp(ifp, AFA_PHASE2) == NULL) { 83 1.32 thorpej /* ifp not an appletalk interface */ 84 1.1 christos m_freem(m); 85 1.1 christos continue; 86 1.1 christos } 87 1.26 plunky ddp_input(m, ifp, NULL, 2); 88 1.1 christos } 89 1.32 thorpej mutex_exit(softnet_lock); 90 1.32 thorpej } 91 1.1 christos 92 1.32 thorpej void 93 1.32 thorpej atintr1(void *arg __unused) 94 1.32 thorpej { 95 1.32 thorpej struct mbuf *m; 96 1.1 christos 97 1.32 thorpej mutex_enter(softnet_lock); 98 1.32 thorpej while ((m = pktq_dequeue(at_pktq1)) != NULL) { 99 1.32 thorpej struct ifnet *ifp; 100 1.32 thorpej struct elaphdr *elhp, elh; 101 1.8 matt 102 1.9 jonathan m_claimm(m, &atalk_rx_mowner); 103 1.27 ozaki ifp = m_get_rcvif_NOMPSAFE(m); 104 1.32 thorpej if (at_ifaddr_for_ifp(ifp, 0) == NULL) { 105 1.32 thorpej /* ifp not an appletalk interface */ 106 1.1 christos m_freem(m); 107 1.1 christos continue; 108 1.1 christos } 109 1.1 christos if (m->m_len < SZ_ELAPHDR && 110 1.1 christos ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) { 111 1.18 thorpej DDP_STATINC(DDP_STAT_TOOSHORT); 112 1.1 christos continue; 113 1.1 christos } 114 1.1 christos elhp = mtod(m, struct elaphdr *); 115 1.1 christos m_adj(m, SZ_ELAPHDR); 116 1.1 christos 117 1.1 christos if (elhp->el_type == ELAP_DDPEXTEND) { 118 1.26 plunky ddp_input(m, ifp, NULL, 1); 119 1.1 christos } else { 120 1.25 tsutsui memcpy((void *) & elh, (void *) elhp, SZ_ELAPHDR); 121 1.1 christos ddp_input(m, ifp, &elh, 1); 122 1.1 christos } 123 1.1 christos } 124 1.19 ad mutex_exit(softnet_lock); 125 1.1 christos } 126 1.1 christos 127 1.1 christos struct route forwro; 128 1.1 christos 129 1.1 christos void 130 1.21 dsl ddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase) 131 1.1 christos { 132 1.16 dyoung struct rtentry *rt; 133 1.1 christos struct sockaddr_at from, to; 134 1.1 christos struct ddpshdr *dsh, ddps; 135 1.1 christos struct at_ifaddr *aa; 136 1.1 christos struct ddpehdr *deh = NULL, ddpe; 137 1.1 christos struct ddpcb *ddp; 138 1.1 christos int dlen, mlen; 139 1.1 christos u_short cksum = 0; 140 1.15 dyoung union { 141 1.15 dyoung struct sockaddr dst; 142 1.15 dyoung struct sockaddr_at dsta; 143 1.15 dyoung } u; 144 1.1 christos 145 1.23 cegger memset((void *) & from, 0, sizeof(struct sockaddr_at)); 146 1.1 christos if (elh) { 147 1.18 thorpej DDP_STATINC(DDP_STAT_SHORT); 148 1.1 christos 149 1.1 christos if (m->m_len < sizeof(struct ddpshdr) && 150 1.1 christos ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) { 151 1.18 thorpej DDP_STATINC(DDP_STAT_TOOSHORT); 152 1.1 christos return; 153 1.1 christos } 154 1.1 christos dsh = mtod(m, struct ddpshdr *); 155 1.25 tsutsui memcpy((void *) & ddps, (void *) dsh, sizeof(struct ddpshdr)); 156 1.1 christos ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 157 1.1 christos dlen = ddps.dsh_len; 158 1.1 christos 159 1.1 christos to.sat_addr.s_net = ATADDR_ANYNET; 160 1.1 christos to.sat_addr.s_node = elh->el_dnode; 161 1.1 christos to.sat_port = ddps.dsh_dport; 162 1.1 christos from.sat_addr.s_net = ATADDR_ANYNET; 163 1.1 christos from.sat_addr.s_node = elh->el_snode; 164 1.1 christos from.sat_port = ddps.dsh_sport; 165 1.1 christos 166 1.34 riastrad TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 167 1.1 christos if (aa->aa_ifp == ifp && 168 1.1 christos (aa->aa_flags & AFA_PHASE2) == 0 && 169 1.1 christos (AA_SAT(aa)->sat_addr.s_node == 170 1.1 christos to.sat_addr.s_node || 171 1.1 christos to.sat_addr.s_node == ATADDR_BCAST)) 172 1.1 christos break; 173 1.1 christos } 174 1.1 christos if (aa == NULL) { 175 1.1 christos m_freem(m); 176 1.1 christos return; 177 1.1 christos } 178 1.1 christos } else { 179 1.18 thorpej DDP_STATINC(DDP_STAT_LONG); 180 1.1 christos 181 1.1 christos if (m->m_len < sizeof(struct ddpehdr) && 182 1.1 christos ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) { 183 1.18 thorpej DDP_STATINC(DDP_STAT_TOOSHORT); 184 1.1 christos return; 185 1.1 christos } 186 1.1 christos deh = mtod(m, struct ddpehdr *); 187 1.25 tsutsui memcpy((void *) & ddpe, (void *) deh, sizeof(struct ddpehdr)); 188 1.1 christos ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 189 1.1 christos dlen = ddpe.deh_len; 190 1.1 christos 191 1.1 christos if ((cksum = ddpe.deh_sum) == 0) { 192 1.18 thorpej DDP_STATINC(DDP_STAT_NOSUM); 193 1.1 christos } 194 1.1 christos from.sat_addr.s_net = ddpe.deh_snet; 195 1.1 christos from.sat_addr.s_node = ddpe.deh_snode; 196 1.1 christos from.sat_port = ddpe.deh_sport; 197 1.1 christos to.sat_addr.s_net = ddpe.deh_dnet; 198 1.1 christos to.sat_addr.s_node = ddpe.deh_dnode; 199 1.1 christos to.sat_port = ddpe.deh_dport; 200 1.1 christos 201 1.1 christos if (to.sat_addr.s_net == ATADDR_ANYNET) { 202 1.34 riastrad TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 203 1.1 christos if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) 204 1.1 christos continue; 205 1.1 christos 206 1.1 christos if (phase == 2 && 207 1.1 christos (aa->aa_flags & AFA_PHASE2) == 0) 208 1.1 christos continue; 209 1.1 christos 210 1.1 christos if (aa->aa_ifp == ifp && 211 1.1 christos (AA_SAT(aa)->sat_addr.s_node == 212 1.1 christos to.sat_addr.s_node || 213 1.1 christos to.sat_addr.s_node == ATADDR_BCAST || 214 1.1 christos (ifp->if_flags & IFF_LOOPBACK))) 215 1.1 christos break; 216 1.1 christos } 217 1.1 christos } else { 218 1.34 riastrad TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 219 1.1 christos if (to.sat_addr.s_net == aa->aa_firstnet && 220 1.1 christos to.sat_addr.s_node == 0) 221 1.1 christos break; 222 1.1 christos 223 1.1 christos if ((ntohs(to.sat_addr.s_net) < 224 1.1 christos ntohs(aa->aa_firstnet) || 225 1.1 christos ntohs(to.sat_addr.s_net) > 226 1.1 christos ntohs(aa->aa_lastnet)) && 227 1.3 wrstuden (ntohs(to.sat_addr.s_net) < 0xff00 || 228 1.3 wrstuden ntohs(to.sat_addr.s_net) > 0xfffe)) 229 1.1 christos continue; 230 1.1 christos 231 1.1 christos if (to.sat_addr.s_node != 232 1.1 christos AA_SAT(aa)->sat_addr.s_node && 233 1.1 christos to.sat_addr.s_node != ATADDR_BCAST) 234 1.1 christos continue; 235 1.1 christos 236 1.1 christos break; 237 1.1 christos } 238 1.1 christos } 239 1.1 christos } 240 1.1 christos 241 1.1 christos /* 242 1.1 christos * Adjust the length, removing any padding that may have been added 243 1.1 christos * at a link layer. We do this before we attempt to forward a packet, 244 1.1 christos * possibly on a different media. 245 1.1 christos */ 246 1.1 christos mlen = m->m_pkthdr.len; 247 1.1 christos if (mlen < dlen) { 248 1.18 thorpej DDP_STATINC(DDP_STAT_TOOSMALL); 249 1.1 christos m_freem(m); 250 1.1 christos return; 251 1.1 christos } 252 1.1 christos if (mlen > dlen) { 253 1.1 christos m_adj(m, dlen - mlen); 254 1.1 christos } 255 1.1 christos /* 256 1.1 christos * XXX Should we deliver broadcasts locally, also, or rely on the 257 1.1 christos * link layer to give us a copy? For the moment, the latter. 258 1.1 christos */ 259 1.1 christos if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST && 260 1.1 christos aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) { 261 1.1 christos if (ddp_forward == 0) { 262 1.1 christos m_freem(m); 263 1.1 christos return; 264 1.1 christos } 265 1.15 dyoung sockaddr_at_init(&u.dsta, &to.sat_addr, 0); 266 1.17 dyoung rt = rtcache_lookup(&forwro, &u.dst); 267 1.15 dyoung #if 0 /* XXX The if-condition is always false. What was this 268 1.15 dyoung * actually trying to test? 269 1.15 dyoung */ 270 1.1 christos if (to.sat_addr.s_net != 271 1.13 dyoung satocsat(rtcache_getdst(&forwro))->sat_addr.s_net && 272 1.1 christos ddpe.deh_hops == DDP_MAXHOPS) { 273 1.1 christos m_freem(m); 274 1.1 christos return; 275 1.1 christos } 276 1.15 dyoung #endif 277 1.17 dyoung if (ddp_firewall && (rt == NULL || rt->rt_ifp != ifp)) { 278 1.29 ozaki rtcache_unref(rt, &forwro); 279 1.1 christos m_freem(m); 280 1.1 christos return; 281 1.1 christos } 282 1.29 ozaki rtcache_unref(rt, &forwro); 283 1.1 christos ddpe.deh_hops++; 284 1.1 christos ddpe.deh_bytes = htonl(ddpe.deh_bytes); 285 1.25 tsutsui memcpy((void *) deh, (void *) & ddpe, sizeof(u_short));/*XXX*/ 286 1.1 christos if (ddp_route(m, &forwro)) { 287 1.18 thorpej DDP_STATINC(DDP_STAT_CANTFORWARD); 288 1.1 christos } else { 289 1.18 thorpej DDP_STATINC(DDP_STAT_FORWARD); 290 1.1 christos } 291 1.1 christos return; 292 1.1 christos } 293 1.1 christos from.sat_len = sizeof(struct sockaddr_at); 294 1.1 christos from.sat_family = AF_APPLETALK; 295 1.1 christos 296 1.1 christos if (elh) { 297 1.1 christos m_adj(m, sizeof(struct ddpshdr)); 298 1.1 christos } else { 299 1.1 christos if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { 300 1.18 thorpej DDP_STATINC(DDP_STAT_BADSUM); 301 1.1 christos m_freem(m); 302 1.1 christos return; 303 1.1 christos } 304 1.1 christos m_adj(m, sizeof(struct ddpehdr)); 305 1.1 christos } 306 1.1 christos 307 1.1 christos if ((ddp = ddp_search(&from, &to, aa)) == NULL) { 308 1.1 christos m_freem(m); 309 1.1 christos return; 310 1.1 christos } 311 1.1 christos if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from, 312 1.1 christos m, (struct mbuf *) 0) == 0) { 313 1.18 thorpej DDP_STATINC(DDP_STAT_NOSOCKSPACE); 314 1.31 roy soroverflow(ddp->ddp_socket); 315 1.1 christos m_freem(m); 316 1.1 christos return; 317 1.1 christos } 318 1.4 aidan #if IFA_STATS 319 1.4 aidan if (aa) 320 1.4 aidan aa->aa_ifa.ifa_data.ifad_inbytes += dlen; 321 1.4 aidan #endif 322 1.1 christos sorwakeup(ddp->ddp_socket); 323 1.1 christos } 324 1.1 christos 325 1.1 christos #if 0 326 1.1 christos 327 1.1 christos #define BPXLEN 48 328 1.1 christos #define BPALEN 16 329 1.1 christos #include <ctype.h> 330 1.1 christos 331 1.1 christos static void 332 1.21 dsl bprint(char *data, int len) 333 1.1 christos { 334 1.1 christos char xout[BPXLEN], aout[BPALEN]; 335 1.1 christos int i = 0; 336 1.1 christos 337 1.23 cegger memset(xout, 0, BPXLEN); 338 1.23 cegger memset(aout, 0, BPALEN); 339 1.1 christos 340 1.1 christos for (;;) { 341 1.1 christos if (len < 1) { 342 1.1 christos if (i != 0) { 343 1.1 christos printf("%s\t%s\n", xout, aout); 344 1.1 christos } 345 1.1 christos printf("%s\n", "(end)"); 346 1.1 christos break; 347 1.1 christos } 348 1.10 christos xout[(i * 3)] = hexdigits[(*data & 0xf0) >> 4]; 349 1.10 christos xout[(i * 3) + 1] = hexdigits[*data & 0x0f]; 350 1.1 christos 351 1.1 christos if ((u_char) * data < 0x7f && (u_char) * data > 0x20) { 352 1.1 christos aout[i] = *data; 353 1.1 christos } else { 354 1.1 christos aout[i] = '.'; 355 1.1 christos } 356 1.1 christos 357 1.1 christos xout[(i * 3) + 2] = ' '; 358 1.1 christos 359 1.1 christos i++; 360 1.1 christos len--; 361 1.1 christos data++; 362 1.1 christos 363 1.1 christos if (i > BPALEN - 2) { 364 1.1 christos printf("%s\t%s\n", xout, aout); 365 1.23 cegger memset(xout, 0, BPXLEN); 366 1.23 cegger memset(aout, 0, BPALEN); 367 1.1 christos i = 0; 368 1.1 christos continue; 369 1.1 christos } 370 1.1 christos } 371 1.1 christos } 372 1.1 christos 373 1.1 christos static void 374 1.21 dsl m_printm(struct mbuf *m) 375 1.1 christos { 376 1.1 christos for (; m; m = m->m_next) 377 1.1 christos bprint(mtod(m, char *), m->m_len); 378 1.1 christos } 379 1.1 christos #endif 380