1 /* $NetBSD: ddp_input.c,v 1.9 2004/06/24 04:15:51 jonathan 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.9 2004/06/24 04:15:51 jonathan 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((caddr_t) elhp, (caddr_t) & 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 148 bzero((caddr_t) & from, sizeof(struct sockaddr_at)); 149 if (elh) { 150 ddpstat.ddps_short++; 151 152 if (m->m_len < sizeof(struct ddpshdr) && 153 ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) { 154 ddpstat.ddps_tooshort++; 155 return; 156 } 157 dsh = mtod(m, struct ddpshdr *); 158 bcopy((caddr_t) dsh, (caddr_t) & ddps, sizeof(struct ddpshdr)); 159 ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 160 dlen = ddps.dsh_len; 161 162 to.sat_addr.s_net = ATADDR_ANYNET; 163 to.sat_addr.s_node = elh->el_dnode; 164 to.sat_port = ddps.dsh_dport; 165 from.sat_addr.s_net = ATADDR_ANYNET; 166 from.sat_addr.s_node = elh->el_snode; 167 from.sat_port = ddps.dsh_sport; 168 169 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 170 if (aa->aa_ifp == ifp && 171 (aa->aa_flags & AFA_PHASE2) == 0 && 172 (AA_SAT(aa)->sat_addr.s_node == 173 to.sat_addr.s_node || 174 to.sat_addr.s_node == ATADDR_BCAST)) 175 break; 176 } 177 if (aa == NULL) { 178 m_freem(m); 179 return; 180 } 181 } else { 182 ddpstat.ddps_long++; 183 184 if (m->m_len < sizeof(struct ddpehdr) && 185 ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) { 186 ddpstat.ddps_tooshort++; 187 return; 188 } 189 deh = mtod(m, struct ddpehdr *); 190 bcopy((caddr_t) deh, (caddr_t) & ddpe, sizeof(struct ddpehdr)); 191 ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 192 dlen = ddpe.deh_len; 193 194 if ((cksum = ddpe.deh_sum) == 0) { 195 ddpstat.ddps_nosum++; 196 } 197 from.sat_addr.s_net = ddpe.deh_snet; 198 from.sat_addr.s_node = ddpe.deh_snode; 199 from.sat_port = ddpe.deh_sport; 200 to.sat_addr.s_net = ddpe.deh_dnet; 201 to.sat_addr.s_node = ddpe.deh_dnode; 202 to.sat_port = ddpe.deh_dport; 203 204 if (to.sat_addr.s_net == ATADDR_ANYNET) { 205 for (aa = at_ifaddr.tqh_first; aa; 206 aa = aa->aa_list.tqe_next) { 207 if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) 208 continue; 209 210 if (phase == 2 && 211 (aa->aa_flags & AFA_PHASE2) == 0) 212 continue; 213 214 if (aa->aa_ifp == ifp && 215 (AA_SAT(aa)->sat_addr.s_node == 216 to.sat_addr.s_node || 217 to.sat_addr.s_node == ATADDR_BCAST || 218 (ifp->if_flags & IFF_LOOPBACK))) 219 break; 220 } 221 } else { 222 for (aa = at_ifaddr.tqh_first; aa; 223 aa = aa->aa_list.tqe_next) { 224 if (to.sat_addr.s_net == aa->aa_firstnet && 225 to.sat_addr.s_node == 0) 226 break; 227 228 if ((ntohs(to.sat_addr.s_net) < 229 ntohs(aa->aa_firstnet) || 230 ntohs(to.sat_addr.s_net) > 231 ntohs(aa->aa_lastnet)) && 232 (ntohs(to.sat_addr.s_net) < 0xff00 || 233 ntohs(to.sat_addr.s_net) > 0xfffe)) 234 continue; 235 236 if (to.sat_addr.s_node != 237 AA_SAT(aa)->sat_addr.s_node && 238 to.sat_addr.s_node != ATADDR_BCAST) 239 continue; 240 241 break; 242 } 243 } 244 } 245 246 /* 247 * Adjust the length, removing any padding that may have been added 248 * at a link layer. We do this before we attempt to forward a packet, 249 * possibly on a different media. 250 */ 251 mlen = m->m_pkthdr.len; 252 if (mlen < dlen) { 253 ddpstat.ddps_toosmall++; 254 m_freem(m); 255 return; 256 } 257 if (mlen > dlen) { 258 m_adj(m, dlen - mlen); 259 } 260 /* 261 * XXX Should we deliver broadcasts locally, also, or rely on the 262 * link layer to give us a copy? For the moment, the latter. 263 */ 264 if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST && 265 aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) { 266 if (ddp_forward == 0) { 267 m_freem(m); 268 return; 269 } 270 if (forwro.ro_rt && 271 (satosat(&forwro.ro_dst)->sat_addr.s_net != 272 to.sat_addr.s_net || 273 satosat(&forwro.ro_dst)->sat_addr.s_node != 274 to.sat_addr.s_node)) { 275 RTFREE(forwro.ro_rt); 276 forwro.ro_rt = (struct rtentry *) 0; 277 } 278 if (forwro.ro_rt == (struct rtentry *) 0 || 279 forwro.ro_rt->rt_ifp == (struct ifnet *) 0) { 280 bzero(&forwro.ro_dst, sizeof(struct sockaddr_at)); 281 forwro.ro_dst.sa_len = sizeof(struct sockaddr_at); 282 forwro.ro_dst.sa_family = AF_APPLETALK; 283 satosat(&forwro.ro_dst)->sat_addr.s_net = 284 to.sat_addr.s_net; 285 satosat(&forwro.ro_dst)->sat_addr.s_node = 286 to.sat_addr.s_node; 287 rtalloc(&forwro); 288 } 289 if (to.sat_addr.s_net != 290 satosat(&forwro.ro_dst)->sat_addr.s_net && 291 ddpe.deh_hops == DDP_MAXHOPS) { 292 m_freem(m); 293 return; 294 } 295 if (ddp_firewall && 296 (forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp != ifp)) { 297 m_freem(m); 298 return; 299 } 300 ddpe.deh_hops++; 301 ddpe.deh_bytes = htonl(ddpe.deh_bytes); 302 bcopy((caddr_t) & ddpe, (caddr_t) deh, sizeof(u_short));/*XXX*/ 303 if (ddp_route(m, &forwro)) { 304 ddpstat.ddps_cantforward++; 305 } else { 306 ddpstat.ddps_forward++; 307 } 308 return; 309 } 310 from.sat_len = sizeof(struct sockaddr_at); 311 from.sat_family = AF_APPLETALK; 312 313 if (elh) { 314 m_adj(m, sizeof(struct ddpshdr)); 315 } else { 316 if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { 317 ddpstat.ddps_badsum++; 318 m_freem(m); 319 return; 320 } 321 m_adj(m, sizeof(struct ddpehdr)); 322 } 323 324 if ((ddp = ddp_search(&from, &to, aa)) == NULL) { 325 m_freem(m); 326 return; 327 } 328 if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from, 329 m, (struct mbuf *) 0) == 0) { 330 ddpstat.ddps_nosockspace++; 331 m_freem(m); 332 return; 333 } 334 #if IFA_STATS 335 if (aa) 336 aa->aa_ifa.ifa_data.ifad_inbytes += dlen; 337 #endif 338 sorwakeup(ddp->ddp_socket); 339 } 340 341 #if 0 342 343 #define BPXLEN 48 344 #define BPALEN 16 345 #include <ctype.h> 346 char hexdig[] = "0123456789ABCDEF"; 347 348 static void 349 bprint(data, len) 350 char *data; 351 int len; 352 { 353 char xout[BPXLEN], aout[BPALEN]; 354 int i = 0; 355 356 bzero(xout, BPXLEN); 357 bzero(aout, BPALEN); 358 359 for (;;) { 360 if (len < 1) { 361 if (i != 0) { 362 printf("%s\t%s\n", xout, aout); 363 } 364 printf("%s\n", "(end)"); 365 break; 366 } 367 xout[(i * 3)] = hexdig[(*data & 0xf0) >> 4]; 368 xout[(i * 3) + 1] = hexdig[*data & 0x0f]; 369 370 if ((u_char) * data < 0x7f && (u_char) * data > 0x20) { 371 aout[i] = *data; 372 } else { 373 aout[i] = '.'; 374 } 375 376 xout[(i * 3) + 2] = ' '; 377 378 i++; 379 len--; 380 data++; 381 382 if (i > BPALEN - 2) { 383 printf("%s\t%s\n", xout, aout); 384 bzero(xout, BPXLEN); 385 bzero(aout, BPALEN); 386 i = 0; 387 continue; 388 } 389 } 390 } 391 392 static void 393 m_printm(m) 394 struct mbuf *m; 395 { 396 for (; m; m = m->m_next) 397 bprint(mtod(m, char *), m->m_len); 398 } 399 #endif 400