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