00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #include <sys/confnet.h>
00063 #include <sys/confos.h>
00064 #include <sys/thread.h>
00065 #include <sys/timer.h>
00066 #include <sys/socket.h>
00067
00068 #include <netinet/in.h>
00069 #include <net/if_var.h>
00070
00071 #include <stdlib.h>
00072 #include <string.h>
00073 #include <memdebug.h>
00074
00075 #include <pro/discover.h>
00076
00081
00082 #ifndef NUT_THREAD_DISTSTACK
00083 #if defined(__AVR__)
00084 #if defined(__GNUC__)
00085
00086 #define NUT_THREAD_DISTSTACK 224
00087 #else
00088
00089 #define NUT_THREAD_DISTSTACK 384
00090 #endif
00091 #else
00092
00093 #define NUT_THREAD_DISTSTACK 320
00094 #endif
00095 #endif
00096
00097 #ifndef DISCOVERY_PORT
00098 #define DISCOVERY_PORT 9806
00099 #endif
00100
00101 typedef struct {
00102 uint32_t disopt_ipmask;
00103 uint16_t disopt_port;
00104 unsigned int disopt_flags;
00105 } DISCOVERY_OPTIONS;
00106
00107 static DISCOVERY_OPTIONS disopt;
00108 static uint32_t xid;
00109
00110 static int NutDiscoveryHandler(uint32_t ip, uint16_t port, DISCOVERY_TELE * dist, int len);
00111 static NutDiscoveryCallback discovery_callback = NutDiscoveryHandler;
00112
00120 int NutDiscoveryAnnTele(DISCOVERY_TELE * dist)
00121 {
00122 memset(dist, 0, sizeof(DISCOVERY_TELE));
00123 dist->dist_xid = xid;
00124 dist->dist_type = DIST_ANNOUNCE;
00125 dist->dist_ver = DISCOVERY_VERSION;
00126 memcpy(dist->dist_mac, confnet.cdn_mac, sizeof(dist->dist_mac));
00127 dist->dist_ip_addr = confnet.cdn_ip_addr;
00128 dist->dist_ip_mask = confnet.cdn_ip_mask;
00129 dist->dist_gateway = confnet.cdn_gateway;
00130 dist->dist_cip_addr = confnet.cdn_cip_addr;
00131 #if DISCOVERY_VERSION <= 0x10
00132 memcpy(dist->dist_hostname, confos.hostname, sizeof(dist->dist_hostname));
00133 return sizeof(DISCOVERY_TELE) - sizeof(dist->dist_custom);
00134 #else
00135 dist->dist_appendix[0] = (uint8_t)strlen(confos.hostname);
00136 memcpy(&dist->dist_appendix[1], confos.hostname, dist->dist_appendix[0]);
00137 return sizeof(DISCOVERY_TELE) - sizeof(dist->dist_appendix) + dist->dist_appendix[0] + 1;
00138 #endif
00139 }
00140
00148 int NutDiscoveryAppConf(DISCOVERY_TELE * dist)
00149 {
00150 memset(confos.hostname, 0, sizeof(confos.hostname));
00151 #if DISCOVERY_VERSION <= 0x10
00152 strncpy(confos.hostname, (char *)dist->dist_hostname, sizeof(confos.hostname) - 1);
00153 #else
00154 memcpy(confos.hostname, &dist->dist_appendix[1], dist->dist_appendix[0]);
00155 #endif
00156 NutSaveConfig();
00157
00158 memcpy(confnet.cdn_mac, dist->dist_mac, sizeof(confnet.cdn_mac));
00159 confnet.cdn_ip_addr = dist->dist_ip_addr;
00160 confnet.cdn_ip_mask = dist->dist_ip_mask;
00161 confnet.cdn_gateway = dist->dist_gateway;
00162 confnet.cdn_cip_addr = dist->dist_cip_addr;
00163
00164 return NutNetSaveConfig();
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 static int NutDiscoveryHandler(uint32_t ip, uint16_t port, DISCOVERY_TELE * dist, int len)
00176 {
00177 int rc = -1;
00178 #if DISCOVERY_VERSION <= 0x10
00179 size_t minlen = sizeof(DISCOVERY_TELE) - sizeof(dist->dist_custom);
00180 #else
00181 size_t minlen = sizeof(DISCOVERY_TELE) - sizeof(dist->dist_appendix) + 1;
00182 #endif
00183
00184
00185 if (len >= minlen) {
00186
00187
00188
00189 if (dist->dist_type == DIST_REQUEST) {
00190
00191 rc = NutDiscoveryAnnTele(dist);
00192 }
00193
00194
00195
00196
00197 else if (dist->dist_type == DIST_APPLY
00198
00199 && dist->dist_xid == xid
00200
00201 && dist->dist_ver == DISCOVERY_VERSION) {
00202 xid += NutGetTickCount();
00203
00204 rc = NutDiscoveryAppConf(dist);
00205 }
00206 }
00207 return rc;
00208 }
00209
00210 THREAD(DiscoveryResponder, arg)
00211 {
00212 UDPSOCKET *sock;
00213 DISCOVERY_TELE *dist;
00214 uint32_t raddr;
00215 uint16_t rport;
00216 int len;
00217
00218
00219 while ((dist = malloc(sizeof(DISCOVERY_TELE))) == NULL) {
00220 NutSleep(1000);
00221 }
00222
00223
00224 while ((sock = NutUdpCreateSocket(disopt.disopt_port)) == NULL) {
00225 NutSleep(1000);
00226 }
00227
00228
00229 {
00230 uint16_t max_ms = sizeof(DISCOVERY_TELE) * 3;
00231
00232 NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
00233 }
00234
00235
00236 memcpy(&xid, &confnet.cdn_mac[2], sizeof(xid));
00237 xid += NutGetTickCount();
00238
00239
00240 if (disopt.disopt_flags & DISF_INITAL_ANN) {
00241
00242 NutSleep(500 + (xid & 0x7FF));
00243 if ((len = NutDiscoveryAnnTele(dist)) > 0) {
00244 NutUdpSendTo(sock, INADDR_BROADCAST, disopt.disopt_port, dist, len);
00245 }
00246 }
00247
00248
00249 for (;;) {
00250 len = NutUdpReceiveFrom(sock, &raddr, &rport, dist, sizeof(DISCOVERY_TELE), 0);
00251
00252 if ((raddr & disopt.disopt_ipmask) == raddr && len > 0 && discovery_callback) {
00253 if ((len = discovery_callback(raddr, rport, dist, len)) > 0) {
00254
00255 if ((raddr & confnet.cdn_ip_mask) != (confnet.cdn_ip_addr & confnet.cdn_ip_mask)) {
00256 raddr = INADDR_BROADCAST;
00257 }
00258 NutUdpSendTo(sock, raddr, disopt.disopt_port, dist, len);
00259 }
00260 }
00261
00262 NutSleep(100);
00263 }
00264 }
00265
00280 NutDiscoveryCallback NutRegisterDiscoveryCallback(NutDiscoveryCallback func)
00281 {
00282 NutDiscoveryCallback rc = discovery_callback;
00283
00284 discovery_callback = func;
00285
00286 return rc;
00287 }
00288
00306 int NutRegisterDiscovery(uint32_t ipmask, uint16_t port, unsigned int flags)
00307 {
00308 static HANDLE tid = NULL;
00309
00310 if (tid == NULL) {
00311 disopt.disopt_ipmask = ipmask;
00312 disopt.disopt_port = port ? port : DISCOVERY_PORT;
00313 disopt.disopt_flags = flags;
00314 tid = NutThreadCreate("udisc", DiscoveryResponder, NULL,
00315 (NUT_THREAD_DISTSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD);
00316 if (tid) {
00317 return 0;
00318 }
00319 }
00320 return -1;
00321 }
00322