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