1 /* $NetBSD: ddp_input.c,v 1.29 2016/12/08 05:16:33 ozaki-r 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.29 2016/12/08 05:16:33 ozaki-r Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <net/netisr.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 *, 56 struct elaphdr *, int); 57 58 /* 59 * Could probably merge these two code segments a little better... 60 */ 61 void 62 atintr(void) 63 { 64 struct elaphdr *elhp, elh; 65 struct ifnet *ifp; 66 struct mbuf *m; 67 struct at_ifaddr *aa; 68 69 mutex_enter(softnet_lock); 70 for (;;) { 71 IFQ_LOCK(&atintrq2); 72 IF_DEQUEUE(&atintrq2, m); 73 IFQ_UNLOCK(&atintrq2); 74 75 if (m == 0) /* no more queued packets */ 76 break; 77 78 m_claimm(m, &atalk_rx_mowner); 79 ifp = m_get_rcvif_NOMPSAFE(m); 80 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 81 if (aa->aa_ifp == ifp && (aa->aa_flags & AFA_PHASE2)) 82 break; 83 } 84 if (aa == NULL) { /* ifp not an appletalk interface */ 85 m_freem(m); 86 continue; 87 } 88 ddp_input(m, ifp, NULL, 2); 89 } 90 91 for (;;) { 92 IFQ_LOCK(&atintrq1); 93 IF_DEQUEUE(&atintrq1, m); 94 IFQ_UNLOCK(&atintrq1); 95 96 if (m == 0) /* no more queued packets */ 97 98 break; 99 100 m_claimm(m, &atalk_rx_mowner); 101 ifp = m_get_rcvif_NOMPSAFE(m); 102 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 103 if (aa->aa_ifp == ifp && 104 (aa->aa_flags & AFA_PHASE2) == 0) 105 break; 106 } 107 if (aa == NULL) { /* ifp not an appletalk interface */ 108 m_freem(m); 109 continue; 110 } 111 if (m->m_len < SZ_ELAPHDR && 112 ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) { 113 DDP_STATINC(DDP_STAT_TOOSHORT); 114 continue; 115 } 116 elhp = mtod(m, struct elaphdr *); 117 m_adj(m, SZ_ELAPHDR); 118 119 if (elhp->el_type == ELAP_DDPEXTEND) { 120 ddp_input(m, ifp, NULL, 1); 121 } else { 122 memcpy((void *) & elh, (void *) elhp, SZ_ELAPHDR); 123 ddp_input(m, ifp, &elh, 1); 124 } 125 } 126 mutex_exit(softnet_lock); 127 } 128 129 struct route forwro; 130 131 void 132 ddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase) 133 { 134 struct rtentry *rt; 135 struct sockaddr_at from, to; 136 struct ddpshdr *dsh, ddps; 137 struct at_ifaddr *aa; 138 struct ddpehdr *deh = NULL, ddpe; 139 struct ddpcb *ddp; 140 int dlen, mlen; 141 u_short cksum = 0; 142 union { 143 struct sockaddr dst; 144 struct sockaddr_at dsta; 145 } u; 146 147 memset((void *) & from, 0, sizeof(struct sockaddr_at)); 148 if (elh) { 149 DDP_STATINC(DDP_STAT_SHORT); 150 151 if (m->m_len < sizeof(struct ddpshdr) && 152 ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) { 153 DDP_STATINC(DDP_STAT_TOOSHORT); 154 return; 155 } 156 dsh = mtod(m, struct ddpshdr *); 157 memcpy((void *) & ddps, (void *) dsh, sizeof(struct ddpshdr)); 158 ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 159 dlen = ddps.dsh_len; 160 161 to.sat_addr.s_net = ATADDR_ANYNET; 162 to.sat_addr.s_node = elh->el_dnode; 163 to.sat_port = ddps.dsh_dport; 164 from.sat_addr.s_net = ATADDR_ANYNET; 165 from.sat_addr.s_node = elh->el_snode; 166 from.sat_port = ddps.dsh_sport; 167 168 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 169 if (aa->aa_ifp == ifp && 170 (aa->aa_flags & AFA_PHASE2) == 0 && 171 (AA_SAT(aa)->sat_addr.s_node == 172 to.sat_addr.s_node || 173 to.sat_addr.s_node == ATADDR_BCAST)) 174 break; 175 } 176 if (aa == NULL) { 177 m_freem(m); 178 return; 179 } 180 } else { 181 DDP_STATINC(DDP_STAT_LONG); 182 183 if (m->m_len < sizeof(struct ddpehdr) && 184 ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) { 185 DDP_STATINC(DDP_STAT_TOOSHORT); 186 return; 187 } 188 deh = mtod(m, struct ddpehdr *); 189 memcpy((void *) & ddpe, (void *) deh, sizeof(struct ddpehdr)); 190 ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 191 dlen = ddpe.deh_len; 192 193 if ((cksum = ddpe.deh_sum) == 0) { 194 DDP_STATINC(DDP_STAT_NOSUM); 195 } 196 from.sat_addr.s_net = ddpe.deh_snet; 197 from.sat_addr.s_node = ddpe.deh_snode; 198 from.sat_port = ddpe.deh_sport; 199 to.sat_addr.s_net = ddpe.deh_dnet; 200 to.sat_addr.s_node = ddpe.deh_dnode; 201 to.sat_port = ddpe.deh_dport; 202 203 if (to.sat_addr.s_net == ATADDR_ANYNET) { 204 for (aa = at_ifaddr.tqh_first; aa; 205 aa = aa->aa_list.tqe_next) { 206 if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) 207 continue; 208 209 if (phase == 2 && 210 (aa->aa_flags & AFA_PHASE2) == 0) 211 continue; 212 213 if (aa->aa_ifp == ifp && 214 (AA_SAT(aa)->sat_addr.s_node == 215 to.sat_addr.s_node || 216 to.sat_addr.s_node == ATADDR_BCAST || 217 (ifp->if_flags & IFF_LOOPBACK))) 218 break; 219 } 220 } else { 221 for (aa = at_ifaddr.tqh_first; aa; 222 aa = aa->aa_list.tqe_next) { 223 if (to.sat_addr.s_net == aa->aa_firstnet && 224 to.sat_addr.s_node == 0) 225 break; 226 227 if ((ntohs(to.sat_addr.s_net) < 228 ntohs(aa->aa_firstnet) || 229 ntohs(to.sat_addr.s_net) > 230 ntohs(aa->aa_lastnet)) && 231 (ntohs(to.sat_addr.s_net) < 0xff00 || 232 ntohs(to.sat_addr.s_net) > 0xfffe)) 233 continue; 234 235 if (to.sat_addr.s_node != 236 AA_SAT(aa)->sat_addr.s_node && 237 to.sat_addr.s_node != ATADDR_BCAST) 238 continue; 239 240 break; 241 } 242 } 243 } 244 245 /* 246 * Adjust the length, removing any padding that may have been added 247 * at a link layer. We do this before we attempt to forward a packet, 248 * possibly on a different media. 249 */ 250 mlen = m->m_pkthdr.len; 251 if (mlen < dlen) { 252 DDP_STATINC(DDP_STAT_TOOSMALL); 253 m_freem(m); 254 return; 255 } 256 if (mlen > dlen) { 257 m_adj(m, dlen - mlen); 258 } 259 /* 260 * XXX Should we deliver broadcasts locally, also, or rely on the 261 * link layer to give us a copy? For the moment, the latter. 262 */ 263 if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST && 264 aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) { 265 if (ddp_forward == 0) { 266 m_freem(m); 267 return; 268 } 269 sockaddr_at_init(&u.dsta, &to.sat_addr, 0); 270 rt = rtcache_lookup(&forwro, &u.dst); 271 #if 0 /* XXX The if-condition is always false. What was this 272 * actually trying to test? 273 */ 274 if (to.sat_addr.s_net != 275 satocsat(rtcache_getdst(&forwro))->sat_addr.s_net && 276 ddpe.deh_hops == DDP_MAXHOPS) { 277 m_freem(m); 278 return; 279 } 280 #endif 281 if (ddp_firewall && (rt == NULL || rt->rt_ifp != ifp)) { 282 rtcache_unref(rt, &forwro); 283 m_freem(m); 284 return; 285 } 286 rtcache_unref(rt, &forwro); 287 ddpe.deh_hops++; 288 ddpe.deh_bytes = htonl(ddpe.deh_bytes); 289 memcpy((void *) deh, (void *) & ddpe, sizeof(u_short));/*XXX*/ 290 if (ddp_route(m, &forwro)) { 291 DDP_STATINC(DDP_STAT_CANTFORWARD); 292 } else { 293 DDP_STATINC(DDP_STAT_FORWARD); 294 } 295 return; 296 } 297 from.sat_len = sizeof(struct sockaddr_at); 298 from.sat_family = AF_APPLETALK; 299 300 if (elh) { 301 m_adj(m, sizeof(struct ddpshdr)); 302 } else { 303 if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { 304 DDP_STATINC(DDP_STAT_BADSUM); 305 m_freem(m); 306 return; 307 } 308 m_adj(m, sizeof(struct ddpehdr)); 309 } 310 311 if ((ddp = ddp_search(&from, &to, aa)) == NULL) { 312 m_freem(m); 313 return; 314 } 315 if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from, 316 m, (struct mbuf *) 0) == 0) { 317 DDP_STATINC(DDP_STAT_NOSOCKSPACE); 318 m_freem(m); 319 return; 320 } 321 #if IFA_STATS 322 if (aa) 323 aa->aa_ifa.ifa_data.ifad_inbytes += dlen; 324 #endif 325 sorwakeup(ddp->ddp_socket); 326 } 327 328 #if 0 329 330 #define BPXLEN 48 331 #define BPALEN 16 332 #include <ctype.h> 333 334 static void 335 bprint(char *data, int len) 336 { 337 char xout[BPXLEN], aout[BPALEN]; 338 int i = 0; 339 340 memset(xout, 0, BPXLEN); 341 memset(aout, 0, BPALEN); 342 343 for (;;) { 344 if (len < 1) { 345 if (i != 0) { 346 printf("%s\t%s\n", xout, aout); 347 } 348 printf("%s\n", "(end)"); 349 break; 350 } 351 xout[(i * 3)] = hexdigits[(*data & 0xf0) >> 4]; 352 xout[(i * 3) + 1] = hexdigits[*data & 0x0f]; 353 354 if ((u_char) * data < 0x7f && (u_char) * data > 0x20) { 355 aout[i] = *data; 356 } else { 357 aout[i] = '.'; 358 } 359 360 xout[(i * 3) + 2] = ' '; 361 362 i++; 363 len--; 364 data++; 365 366 if (i > BPALEN - 2) { 367 printf("%s\t%s\n", xout, aout); 368 memset(xout, 0, BPXLEN); 369 memset(aout, 0, BPALEN); 370 i = 0; 371 continue; 372 } 373 } 374 } 375 376 static void 377 m_printm(struct mbuf *m) 378 { 379 for (; m; m = m->m_next) 380 bprint(mtod(m, char *), m->m_len); 381 } 382 #endif 383