Written on 3:25 下午 by Yu Lai
其實Squashfs已經用一陣子了,在用它之前是使用initramfs。
和initramfs相比,Squashfs較不佔記憶體的空間,
因為它是可以跑在mtd上的唯讀型壓縮檔案系統。
但也因為是唯讀的,所以在使用上仍需另外配置ramfs來提供Linux使用。
另外,initramfs和Kernel是包成同一個image的,而Squashfs是分開的。
Squashfs是一套供Linux核心使用的GPL開源唯讀壓縮檔案系統。
Squashfs能夠為檔案系統內的檔案、inode及目錄結構進行壓縮,
並支援最大1024千位元組的區段,以提供更大的壓縮比,
標準版的Squashfs採用gzip的數據壓縮。
Squashfs可以至http://squashfs.sourceforge.net/下載。
目前最新的是4.1版,是提供給Linux Kernel 2.6.29版本使用。
若使用較舊版本的Linux Kernel,請改用3.4版本。
以下是安裝Note,寫的有點亂,請見諒。
另外可以參考SquashFS HOWTO。
1. 裝Linux Kernel上SquashFS patch。
# cd /opt/linux-2.6.xx
# patch -p1 < /opt/squashfs/kernel-patches/linux-2.6.xx/squashfs3.4-patch
2. 修改MTD配置,在Flash上配置出Kernel和Squashfs的partition出來。
(在此共切4個Partition,分別是0-Bootloader, 1-Kernel, 2-Rootfs, 3-Other)
若已經調整好或是使用類似Redboot的fis,可跳過這段。
3. 編Linux Kernel。
# make distclean
# make mrproper
# make menuconfig
在File systems->Miscellaneous file systems將Squashed filesystem啟動(bundled with the kernel)。
# make
4. 編出SquashFS tools (mksquashfs)。
# cd /opt/squashfs/squashfs-tools
# make
5. 將root file system透過mksquashfs來產生image。
# mksquashfs ./root_file_system rootfs.bin
6. 在Loader上用tftp把rootfs.bin載入後燒錄到Partition Rootfs對應在Flash上的Address。
e.g. # flash 0x00100000 0x80100000
7. 修改kernel command line。
請改成 "console=ttyS0 root=/dev/mtdblock2 rootfstype=squashfs"
PS1:
在root file system裡的/etc/fstab裡可加入
ramfs /tmp ramfs defaults 0 0,避免Linux無寫入的File System可以使用。
PS2:
配合mtd,在Linux下亦可以透過mtd tools直接upgrade root file system。
# flash_eraseall /dev/mtd2
# flashcp -v rootfs.bin /dev/mtd2
Posted in
技術,
Embedded,
File System,
Linux,
MTD
|
Written on 12:41 下午 by Yu Lai
最近工作上玩到的,總結一下當Note吧。
主要是Ref: Serial Programming Guide for POSIX Operating Systems。
配合pthread把收跟送的部份分開,
以下是收的部份。
struct tty_q {
int len;
unsigned char buff[TTY_Q_SZ]; /* TTY_Q_SZ=1024 */
} tty_q;
int tty_fd;
pthread_mutex_t tty_mutex;
void * rs232com(void *arg) {
int c=0, len;
struct termios oldtio, newtio;
char buf[256];
pthread_detach(pthread_self());
pthread_mutex_init(&tty_mutex, NULL);
/* Open the rs232 port */
tty_fd = open(TTYDEVICE, O_RDWR|O_NOCTTY);
if (tty_fd < 0) {
perror(TTYDEVICE);
exit(1);
}
/* Get the current options */
tcgetattr(tty_fd, &oldtio);
/* Set new options */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE|CS8|CLOCAL|CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
/* Set the options */
tcflush(tty_fd, TCIFLUSH);
tcsetattr(tty_fd, TCSANOW, &newtio);
while(1) {
len = read(tty_fd, buf, 255);
buf[len]=0;
MCP_LOG("RS-232 recv, len=%03d, buf=%s\n", len, buf);
pthread_mutex_lock(&tty_mutex);
if(tty_q.len + len > TTY_Q_SZ) {
memset(tty_q.buff, 0, TTY_Q_SZ);
tty_q.len = 0;
}
memcpy(&tty_q.buff[tty_q.len], buf, len);
tty_q.len += len;
pthread_mutex_unlock(&tty_mutex);
}
}
而送的部份在這裡。
int rs232send(U8 * buf) {
pthread_mutex_lock(&tty_mutex);
memset(tty_q.buff, 0, TTY_Q_SZ);
tty_q.len = 0;
pthread_mutex_unlock(&tty_mutex);
return write(tty_fd, buf, strlen(buf));
}
Posted in
技術,
C,
Linux,
RS-232
|
Written on 10:55 下午 by Yu Lai
最近買了顆Intel Pentium-M 745 1.80G ES版的CPU來升級我的舊NB,T40。
但裝上後發現CPU只有跑到600Mhz,升級變成降級,囧rz~。
上網一查才發現,原來Linux Kernel裡的speedstep不支援我這顆CPU。
沒辦法,總不能一直跑在600Mhz吧,只好自己改Kernel source code支援它囉。
在Pentium-M的CPU中,無論是Banias或Dothan系列,
都可以透過軟體來控制它的電壓和頻率(透過MSR Register)。
在現行的Linux 2.6.32中,
是透過cpufreq_frequency_table來正確的設定其電壓和頻率。
但Linux Kernel source code裡並沒有把所有的Pentium-M CPU都列進去,
這也導致我的745不能跑全速的原因。
所以我要做的目的就是在source code裡加入745的cpufreq_frequency_table,
讓它能正確的跑到1.80GHz。
當然,解法不只一種,但幾乎都要Kernel,除了上述的方法外,有興趣的人可以參考以下的連結。
Ref: http://www.thinkwiki.org/wiki/Pentium_M_undervolting_and_underclocking
Ref: http://forum.thinkpads.com/viewtopic.php?p=296774
以下則是我修改的過程與筆記。
PS: 由於我的環境是Ubuntu,所以以下的方法是以Ubuntu的為主。
1. 因為要編kernel,所以先準備好以下工具。
apt-get install build-dep gcc
apt-get install kernel-package libncurses5-dev fakeroot wget bzip2
然後把kernel-source抓回來放到/usr/src下。
2. 把kernel source code解開,把 arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c 打開,
在適當位置定義要給745用的cpufreq_frequency_table,並把它設定到cpu_model models[]中。以下是diff檔。
227a228,240
> /* Intel Pentium M processor 745 / 1.80 GHz (Dothan) */
> static struct cpufreq_frequency_table sonoma_1800[] =
> {
> OPEX( 600, 100, 988, 988, 988, 988),
> OPEX( 800, 100, 1052, 1052, 1052, 1036),
> OPEX(1000, 100, 1116, 1100, 1100, 1084),
> OPEX(1200, 100, 1164, 1164, 1148, 1132),
> OPEX(1400, 100, 1228, 1212, 1212, 1180),
> OPEX(1600, 100, 1292, 1276, 1260, 1228),
> OPEX(1800, 100, 1340, 1324, 1308, 1276),
> { .frequency = CPUFREQ_TABLE_END }
> };
>
307a321
> SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1800, 100, "1.80"),
3. 設定kernel/compile的configuration檔。
先把舊的config檔拿來用,至少不用改太多。
cp /boot/config-`uname -r` .config
make menuconfig
選"Load an Alternate Configuration File"把它載進來,再去修改設定。
這裡建議把Loacl version加進去,方便識別。
改完後存檔離開。
4. 編出kernel deb檔。
make-kpkg clean
fakeroot make-kpkg --initrd kernel_image kernel_headers
(這裡就先去泡茶或找些別的事來做吧,因為要花點時間XD。)
5. 安裝kernel deb檔。
編好後切回目錄/usr/src下,會看到多了2個linux-image-xxxx和linux-headers-xxx的deb檔。
dpkg -i linux-image-xxxx.deb
dpkg -i linux-headers-xxxx.deb
安裝完後,記得檢查一下/boot/grub/grub.cfg。
6. 重開機測試。
# cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
1800000
完成。
Posted in
技術,
Linux,
Ubuntu
|
Written on 4:04 下午 by Yu Lai
一般而言,
在開發Embedded System時大都需要用到不同平台的cross-compiler與Toolchains。
而在elinux.org有一篇介紹各家Toolchains的文章,就轉來參考囉。
Ref: http://elinux.org/Toolchains
以下是常見的幾個Toolchains的說明:
CodeSourcery
CodeSourcery develops Sourcery G++, an Eclipse based Integrated Development Environment (IDE) that incorporates the GNU Toolchain (gcc, gdb, etc.) for cross development for numerous target architectures. CodeSourcery provides a "lite" version for ARM, Coldfire, MIPS, SuperH and Power architectures. The toolchains are always very up to date. CodeSourcery contributes enhancements it makes to the GNU Toolchain upstream continually, making it the single largest (by patch count) corporate contributor.
DENX ELDK
The DENX Embedded Linux Development Kit (ELDK) provides a complete and powerful software development environment for embedded and real-time systems. It is available for ARM, PowerPC and MIPS processors and consists of:
Cross Development Tools (Compiler, Assembler, Linker etc.) to develop software for the target system.
Native Tools (Shell, commands and libraries) which provide a standard Linux development environment that runs on the target system.
Firmware (U-Boot) that can be easily ported to new boards and processors.
Linux kernel including the complete source-code with all device drivers, board-support functions etc.
Xenomai - RTOS Emulation framework for systems requiring hard real-time responses.
SELF (Simple Embedded Linux Framework) as fundament to build your embedded systems on.
All components of the ELDK are available for free with complete source code under GPL and other Free Software Licenses. Also, detailed instructions to rebuild all the tools and packages from scratch are included.
The ELDK can be downloaded for free from several mirror sites or ordered on CD-ROM for a nominal charge (99 Euro). To order the CD please contact office@denx.de
Detailed information about the ELDK is available here.
Buildroot
Buildroot is a complete build system based on the Linux Kernel configuration system and supports a wide range of target architectures. It generates root file system images ready to be written to flash. In addition to having a huge number of packages which can be compiled into the image, it also generates a cross toolchain to build those packages from source. Even if you don't want to use buildroot for your root filesystem, it is a useful tool for generating a toolchain. It should be noted however that it only supports uClibc. If you want to use glibc, you'll need something else.
Posted in
工具,
技術,
Embedded,
Linux
|
Written on 10:41 上午 by Yu Lai
這陣子接了新的板子的開發,由於H/W的關係,
加上JTAG數量有限,所以只能先用RS-232來傳image到板子上run。
目前板子上的Loader為舊版本的u-boot,它只有支援Kermit protocol來傳輸。
說到Kermit,在Windows下有名的TeraTerm的檔案傳送功也有支援kermit protocol。
以下就是我在Linux下使用Minicom+Kermit的心得整理;
1. 安裝minicom和ckermit
請先透過apt-get或Synaptic把minicom和ckermit裝起來。
2. 配置ckermit的設定檔
將以下內容放在~/.kermrc裡.
set carrier-watch off
set prefixing all
set parity none
set stop-bits 1
set modem none
set file type bin
set file name lit
set flow-control none
set prompt "Linux Kermit> "
3. 配置minicom
使用minicom -s,到"檔案傳輸協定"或"File Transfer protocols"裡的G和H,
G設定為/usr/bin/kermit -i -l %f -b %b -s Y U Y N N,
H設定為/usr/bin/kermit -i -l %f -b %b -r N D Y N N。
4. 開始傳檔
執行Ctrl+A -> S,接著選完檔案後即可開始傳送檔案了。
PS1:
以上minicom的設定,
可以使用Ctrl+A -> O裡的"儲存設定",
這樣就不用每次都重新設定了。
PS2:
一般而言除了Kermit外,
常見的還有使用x-modem, y-modem或z-modem protocol來傳送。
而minicom都可以配合外掛程式來達到此功能。
Posted in
技術,
kermit,
Linux,
Serial
|
Written on 1:38 上午 by Yu Lai
From: http://www.cnmsdn.com/html/201002/1266986960ID865.html
在kernel子目錄下存放的就是Android的Linux Kernel了, 通過和標準的Linux 2.6.25 Kernel的對比,我們可以發現,其主要增加了以下的內容:
1. 基於ARM架構增加Gold-Fish平台,相應增加的目錄如下:
kernel/arch/arm/mach-goldfish
kernel/include/asm-arm/arch-goldfish
Gold-Fish平台採用的是ARM926T CPU作為BaseBand處理器, 該CPU主頻至少為200M HZ. 採用MSM7201A CPU(ARM 11)作為主CPU, 其主頻為528M HZ.
2. 增加了yaffs2 FLASH文件系統,相應增加的目錄為:
kernel/fs/yaffs2
實際上,Android包經過編譯後生成的system.img和ramdisk.img文件就是yaffs2格式的包.
3. 增加了Android的相關Driver,相應目錄為:
kernel/drivers/android
主要分為:
Android IPC系統: Binder
Android 日誌系統: Logger
Android 電源管理: Power
Android 鬧鐘管理: Alarm
Android 內存控制台: Ram_console
Android 時鐘控制的gpio: Timed_gpio
4. 增加了switch處理, 相應的目錄為:
kernel/drivers/switch/
5. 增加了一種新的共享內存處理方式, 相應增加的文件為:
kernel/mm/ashmem.c
6. 其他為Linux-2.6.25內核所做的補丁等等,例如BlueTooth, 在此不做詳細分析
另外GoldFish平台相關的驅動文件如下:
1. 字符輸出設備:
kernel/drivers/char/goldfish_tty.c
2. 圖像顯示設備: (Frame Buffer)
kernel/drivers/video/goldfishfb.c
3. 鍵盤輸入設備:
kernel/drivers/input/keyboard/goldfish_events.c
4. RTC設備: (Real Time Clock)
kernel/drivers/rtc/rtc-goldfish.c
. USB Device設備:
kernel/drivers/usb/gadget/android_adb.c
6. SD卡設備:
kernel/drivers/mmc/host/goldfish.c
7. FLASH設備:
kernel/drivers/mtd/devices/goldfish_nand.c
kernel/drivers/mtd/devices/goldfish_nand_reg.h
8. LED設備:
kernel/drivers/leds/ledtrig-sleep.c
9. 電源設備:
kernel/drivers/power/goldfish_battery.c
10. 音頻設備:
kernel/arch/arm/mach-goldfish/audio.c
11. 電源管理:
kernel/arch/arm/mach-goldfish/pm.c
12. 時鐘管理:
kernel/arch/arm/mach-goldfish/timer.c
Posted in
技術,
Android,
Linux
|
Written on 12:47 上午 by Yu Lai
Milestone從原本都很正常work的鬧鐘,
從我出差來泰國後, 沒有插著AC充睡覺就開始怪怪的.
後來花了點時間去trace, 才發現原來RTC的interrupt在2.1的firmware被改濫了.
還好有人把新版本的kernel從新的加拿大版的firmware取出來做成SBF.
Ref From: http://and-developers.com/motorola_milestone:sbf
2.1 kernel fix of scheduled CPU wake-ups
This SBF file will flash only the boot.img (kernel+init) from SHOLS_U2_03.10.0: mediafire, rapidshare
It will fix the broken scheduling of Alarm/RTC interrupts on the SHOLS_U2_02.31 and
SHOLS_U2_02.34 systems (kernel problem - alarms delayed).
升級前先把Kernel的版號記錄一下:
2.6.29-omap1 a21146@ca25rhe74 #1
透過上一篇提到的sbf_flash指令,把kernel更新後,版號變成如下:
2.6.29-omap1 rkg683@ca25rhe56 #1
應該是有更新成功吧,就看這幾天鬧鐘正不正常囉。
Posted in
技術,
Android,
Linux
|
Written on 4:45 下午 by Yu Lai
今天在寫Code時,Kernel狂吐schedule_timeout: wrong timeout value fffffd85 from c01595ef。
查了一下Google才發現這是說schedule_timeout被傳了負數的value進去導致的錯誤。
到/proc/ksyms或System.map一查才發現原來是epoll所呼叫的。
比對了一下code才發現原來忘了對timeout variable進行initial與小於0的check,修正後即解決。
Posted in
技術,
Linux
|
Written on 1:09 下午 by Yu Lai
最近在Milestone上玩起adb和Terminal,發現原有的shell真的難用到爆,
再加上一堆指令不內建,於是想自己編busybox來用用。
首先先搞定Milestone的Cross-Compiler,不外乎以下幾種方法:
1. 自己手動抓binutil, gcc等回來自己慢慢編成target=ARM。(PS:會很慢)
2. 到Android Open Source Project的網站抓prebuilt.git裡編好的toolchain。
http://android.git.kernel.org/?p=platform/prebuilt.git;a=tree;f=linux-x86/toolchain/arm-eabi-4.4.0;
點選snapshot即可下載,大概是74mb左右.我是抓arm-eabi-4.4.0的。
3. 到CodeSourcery抓Sourcery G++ Lite Edition for ARM
http://www.codesourcery.com/sgpp/lite/arm點選Download。
接著去抓busybox的原始碼回來,解開後先按make menuconfig進選單,
此時記得把cross-compiler的位置指定好,
同時把Build BusyBox as a static binary (no shared libs)勾選起來。
其實勾選static binary是比較花code size的,但沒辦法,
懶得hack busybox去配合Bionic Libc,要花太多effert。
所幸編出來的code size也不至於爆肥到哪去 XD。
接著把要編出來的applet選好,存好後敲make開始編囉。
編出busybox後,由於Android內的/system預設是read-only的,
所以我們使用adb push的方式先將busybox丟到/data下。
./adb push busybox /data
接著使用adb shell操作把/system重新mount再把busybox丟過去。
./adb shell
$ su <- 變root
# mount -o rw,remount -t yaffs2 /dev/block/mtdblock6 /system
# cd /data
# chmod +x busybox
# ./busybox cp busybox /system/xbin <- 因為內建的cp難用
# cd /system/xbin
# ./busybox --install <- 安裝links
# cd /data
# rm busybox
# mount -o ro,remount -t yaffs2 /dev/block/mtdblock6 /system
# exit
$ exit
接著就可以使用到busybox所提供強大的功能啦 :)
Posted in
技術,
Android,
Busybox,
Linux
|
Written on 10:10 上午 by Yu Lai
其實拿到手機第二天就被我root了。 XD
只是我這陣子忙著弄rstp到現在才有空把這些資訊整理出來。
首先Milestone的Boot Loader除了原本Loader的功能(Load Kernel & FS then Go)外,
還具有2個特別的功能:
1. Program SBF file。
這個功能是Loader提供了一個介面,讓安裝了RSD Lite的PC透過USB連接線,
直接將Image(SBF file)直接燒錄到Milestone的flash裡。
這裡有官方提供的SBF檔,請小心對應版本。
http://and-developers.com/motorola_milestone:sbf
2. Recovery Mode.
這裡提供Apply sdcard:update.zip與factory reset等功能。
而在2.0.1版本前取root的方法不外乎進Loader的Recovery Mode,
將su與Superuser.apk包成update.zip的方式更新到系統中。
但Motorola官方釋出了Milestone 2.1的更新版中的Recovery mode已經使用新的簽證,
所以無法再繼續使用以前的update.zip來騙過系統作假更新,
也就是不吃使用者自訂的update.zip,這導致無法透過此方法取得root。
沒關係,山不轉路轉,既然新的Recovery Mode不能用,我們就把它更新回舊的。
網路上有人把2.0.1的Recovery Mode從2.0.1的更新檔中抽出來并包裝成SBF檔提供使用。
檔案在此:SHOLS_U2_01.14.0_recovery_only.zip (mediafile)或(bandongo)。
接著去下載Motorola工程師專用的RSD Lit軟件並安裝到Windows內,
http://www.multiupload.com/SIYSOH7VTU。
然後如果沒有安裝Motorola USB driver,
請先安裝: Windows 32-bit Driver / Windows 64-bit Driver。
接著先把Milestone關機,接上USB連接線,把鍵盤推開,
按住"上"鍵不放再按電源鍵啟動Milestone。
等到出現Bootloader裡面後,在Windows裡開啟已安裝的Motorola RSD Lite。
接著在RSD Lite軟件上的Filename裡按 [...],指定剛下載的SBF檔案,
然後按[Start]開始還原,待還原程序完成100%時,手機就會自動重啟。
此時你的Milestone就會具有2.1的System與2.0.1的Recovery Mode。
再來去下載milestone_root.zip到電腦裡,http://www.sendspace.com/file/5cvh9e
把檔名改為update.zip放到Micro SD Card的根目錄 / 內。
接著進到Recovey Mode,有2個方法:
1. 先關閉milestone電源,然後推開鍵盤,按住"上"鍵不放再按電源鍵啟動Milestone,
直到看見白色三角形標置。此時可放開按鈕,再長按"音量增大鍵"+"照相鍵"一下,
便進入了 Recovery Mode。
2. 使用Android Debuging Bridge Tool (adb tool),# adb reboot recovery。
Recovey Mode用鍵盤的5方向鍵選到Apply SDcard: Update.zip按下去執行等到
"Install from sd card complete"字句出現。接著選擇"Reboot system now"重啟Milestone,
待開完機後檢查app裡有沒有"Superuser whitelist"存在即可知道有否root成功。
Posted in
技術,
Android,
Linux,
root
|
Written on 11:39 上午 by Yu Lai
一般我們在Linux上可以使用arp這個指令來顯示或設定ARP Table。
而在程式中如果要操作系統的ARP Table的話,除了用system()來呼叫
arp指令外,也可以透過socket fd所提供的ioctl命令來達成,共有3種,
分別是SIOCSARP(設定ARP mapping),SIOCDARP(刪除ARP mapping),
SIOCGARP(獲取ARP mapping)。在操作上需配合struct arpreq,
定義如下:
struct arpreq {
struct sockaddr arp_pa; /* protocol address */
struct sockaddr arp_ha; /* hardware address */
int arp_flags; /* flags */
struct sockaddr arp_netmask; /* netmask of protocol address */
char arp_dev[16];
};
其中,arp_pa必須是AF_INET的socket。而指定的network device
也必須填入arp_dev中。而arp_flag的value定義如下:
ATF_COM = Lookup complete
ATF_PERM = Permanent entry
ATF_PUBL = Publish entry
ATF_USETRAILERS = Trailers requested
ATF_NETMASK = Use a netmask
ATF_DONTPUB = Don't answer
使用SIOCSARP命令時,需設定arpreq的arp_pa,arp_ha和arp_flags。
此時若ARP Table己經存在這筆IP位址,它會將它取出更新。若不存在,則新增。
使用SIOCDARP命令時,只需設定arpreq中的arp_pa和arp_dev,kernel會
根據arp_pa的IP位址從ARP Table的hash中取出,並將其state更新為NUD_FAILED。
這樣在下一次ARP GC時就會被清掉。
使用SIOCGARP命令時,只需要設定arpreq中的arp_pa即可。不過一般我們
不會透過SIOCGARP命令,而是使用/proc/net/arp直接讀取。
以下是SIOCSARP的範例程式:
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
int set_arp(char * ip, char * mac, char * dev) {
struct arpreq req;
struct sockaddr_in addr;
int sockfd, rc;
unsigned int s_addr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0) {
return 1;
}
/* Inet sockaddr_in struct */
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
/* ARP arpreq struct */
memset(&req, 0, sizeof(req));
memcpy(&req.arp_pa, &addr, sizeof(struct sockaddr));
memcpy(req.arp_ha.sa_data, mac, 6);
req.arp_flags = ATF_PERM | ATF_COM;
strcpy(req.arp_dev, dev);
rc = ioctl(sockfd, SIOCSARP, &req);
close(sockfd);
return rc;
}
Posted in
C,
Linux,
Network
|
Written on 2:03 上午 by Yu Lai
Wine是一種在類Unix系統上執行Windows程式的軟體,
它可以在Ubuntu上跑一些Windows的程式。
會使用這功能主要是要跑Holux M-1000C附的ezTour,
雖然己成功將GPS配合Google Earth來使用,
但我仍未找出怎麼讀出M-1000C內路徑的方法,
現階段只好先透過Wine來跑囉。
不過ezTour要使用COM Port來存取GPS的資料,
在使用前要先將Wine設定好mapping COM Port,
設定方式是先在 ~/.wine/dosdevices 目錄下建立一個link,
e.g.
# ln -s /dev/rfcomm0 com1
這樣透過Wine開啟的ezTour就可以指定COM1來讀出rfcomm0內的資料啦。
Posted in
技術,
COM,
GPS,
Linux,
Serial,
Wine
|
Written on 12:10 下午 by Yu Lai
本篇介紹為了這次出差買的Holux M-1000C GPS在Ubuntu
下配合Google Earth來達到即時定位.
1. 首先當然是要先讓Ubuntu與Holux M-1000C連線
Holux M-1000C本身主要是用藍芽的方式與NB或手機連線,
它也有提供特殊的USB線可以直接轉成RS-232的方式連結,
但這條線我沒買,有機會下次再介紹這條特別的線。
在Ubuntu下用GUI的藍芽只能完成初步的連線,至於GPS常用
的SPP只能在Terminal下指令了,方式如下:
先scan藍芽,把M-1000C的MAC記下來。
# hcitool scan
Scanning ...
00:1B:C1:05:9C:64 Holux M-1000C
接著查看GPS使用的RFCOMM的channel。
# sdptool browser 00:1B:C1:05:9C:64
Browsing 00:1B:C1:05:9C:64 ...
Service Name: SPP slave
Service RecHandle: 0x10000
Service Class ID List:
"Serial Port" (0x1101)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
最後編輯/etc/bluetooth/rfcomm.conf建立rfcomm介面:
rfcomm0 {
bind yes;
device 00:1B:C1:05:9C:64;
channel 1;
comment “Holux M-1000C”;
}
重啟Bluetooth services
/etc/init.d/bluetooth stop
(wait a while)
/etc/init.d/bluetooth start
2. 安裝與設定Google Earth
Google Earth自行到Google網頁上抓就有了,我是抓5.1beta版本。
接下來我們要利用了Google Earth的KML以及KML可以refresh的功能,
來達到即時定位的目的。
預設Google Earth會安裝在/opt/google-earth目錄下,
在該目錄下建立一個Realtime GPS.kml,內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<NetworkLink>
<name>Realtime GPS</name>
<open>1</open>
<Link>
<href>./realtime/Realtime GPS.kml</href>
<refreshMode>onInterval</refreshMode>
</Link>
</NetworkLink>
</kml>
接著把相關目錄realtime建立出來:
# mkdir /opt/google-earth/realtime
接著打開Google Earth,它建好的KML開啟放在Places下(檔案 -> 開啟...)。
3. 從M-1000C取出NMEA定位資料
我們剛才己經將RFCOMM介面設定好了,接著只要下
# rfcomm connect 0
syntax error line 23
Connected /dev/rfcomm0 to 00:1B:C1:05:9C:64 on channel 1
Press CTRL-C for hangup
然後另外開一個Terminal就可以從/dev/rfcomm0內取到M-1000C回報的定位資料了。
e.g.
# cat /dev/rfcomm0
$GPGGA,044423.000,0910.5038,N,09916.9805,E,1,9,0.89,8.6,M,-24.3,M,,*72
$GPRMC,044423.000,A,0910.5038,N,09916.9805,E,0.03,0.00,311009,,,A*67
$GPVTG,0.00,T,,M,0.03,N,0.06,K,A*38
$GPGGA,044424.000,0910.5038,N,09916.9805,E,1,9,0.89,8.6,M,-24.3,M,,*75
$GPRMC,044424.000,A,0910.5038,N,09916.9805,E,0.06,0.00,311009,,,A*65
$GPVTG,0.00,T,,M,0.06,N,0.10,K,A*3A
...
所以接下來就是要拆NMEA的format將它轉成剛才在Google Earth設定realtime的KML檔,
提供給Google Earth讀取並顥示即時位置了。
(PS:NMEA格式可以到
GPS - NMEA sentence information參考。)
以下是我自己寫的C Code,是將NMEA中的GPRMC格式轉成KML,
當然可以依照自喜歡的格式和語言自己改寫。
/*
* filename: gps2kml.c
* author: lazyf (lazyflai (at) gmail.com)
* date: 2009/10/31
* copyright: http://creativecommons.org/licenses/by-nc-nd/2.5/tw/
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#define DEV_FILE "/dev/rfcomm0"
#define KML_FILE "/opt/google-earth/realtime/Realtime GPS.kml"
int main(int argc, char *argv[]) {
char strbuf[256];
char *strp;
FILE *fp, *fp2;
float latitude, latitude_in, latitude_degrees, latitude_minutes;
float longitude, longitude_in, longitude_degrees, longitude_minutes;
float altitude, speed;
/* Call rfcomm connect */
system("rfcomm release 0");
sleep(3);
system("rfcomm connect 0 &");
sleep(5);
/* Open device file */
if((fp = fopen(DEV_FILE, "r"))) {
/* Call Google Earth up */
system("/opt/google-earth/googleearth &");
while(1) {
/* Read text */
memset(strbuf, 0, sizeof(strbuf));
fscanf(fp, "%s\n", strbuf);
if(strlen(strbuf) < 58)
continue;
/* Parse GPRMC format */
if(memcmp(strbuf, "$GPRMC", 6)==0) {
strp = (char *)strtok(strbuf, ","); /* $GPRMC */
strp = (char *)strtok(0, ","); /* Time */
strp = (char *)strtok(0, ","); /* Avalible or Void */
strp = (char *)strtok(0, ","); /* Latitude */
latitude_in = atof(strp);
strp = (char *)strtok(0, ","); /* N or S */
if(strcmp(strp, "S") == 0)
latitude_in = -latitude_in;
latitude_degrees = (int)(latitude_in/100);
latitude_minutes = latitude_in - latitude_degrees*100;
latitude = latitude_degrees + (latitude_minutes/60);
strp = (char *)strtok(0, ","); /* Longitude */
longitude_in = atof(strp);
strp = (char *)strtok(0, ","); /* E or W */
if(strcmp(strp, "W") == 0)
longitude_in = -longitude_in;
longitude_degrees = (int)(longitude_in/100);
longitude_minutes = longitude_in - longitude_degrees*100;
longitude = longitude_degrees + (longitude_minutes/60);
strp = (char *)strtok(0, ","); /* Speed */
speed = atof(strp) * 1.852;
if(speed < 3)
speed = 0;
strp = (char *)strtok(0, ","); /* Altitude */
altitude = atof(strp);
/* Output KML file */
if((fp2 = fopen(KML_FILE, "w"))) {
fprintf(fp2,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<kml xmlns=\"http://earth.google.com/kml/2.0\">\n"
"\t<Placemark>\n"
"\t\t<name>GPS %d.%d km/h</name>\n"
"\t\t<description></description>\n"
"\t\t<Point>\n\t\t\t<coordinates>%f,%f,%f</coordinates>\n\t\t</Point>\n"
"\t</Placemark>\n"
"</kml>\n",
(int)speed, ((int)(speed*10))%10, longitude, latitude, altitude);
fflush(fp2);
fclose(fp2);
}
}
}
fclose(fp);
}
return 0;
}
最後把它compile出來執行,就會自動建好rfcomm0和開啟Google Earth啦。
Posted in
技術,
GPS,
Linux
|
Written on 2:55 上午 by Yu Lai
之前買的pcmcia介面的SmartCard Reader,沒想到裝在Linux上有點麻煩。
首先到官網上 http://www.scm-pc-card.eu/ 抓Driver回來。
安裝前請先透過apt-get安裝以下套件:
apt-get install libusb-0.1-4 libpcsclite1 libpcsclite-dev pcscd pcsc-tools build-essential autoconf libccid
接著把Driver解開,執行它的install檔,不過我抓的v4.2.6好像在判斷pcsclite有問題,
手動將install內的判斷式修改一下即可。
./install
接著到 /dev 下手動將device node建立出來
cd /dev
mknod SCR24x0 c 251 0
udev也要
cd /lib/udev/devices
mknod SCR24x0 c 251 0
然後重新啟動電腦,讓剛才編好的driver與pcscd載入,
可用以下指令來判斷是否載作成功:
# lspcmcia -v
Socket 0 Bridge: [yenta_cardbus] (bus ID: 0000:06:09.0)
Configuration: state: on ready: unknown
Voltage: 5.0V Vcc: 5.0V Vpp: 0.0V
Socket 0 Device 0: [scr24x_cs] (bus ID: 0.0)
Configuration: state: on
Product Name: SCR243 PCMCIA Smart Card Reader
Identification: manf_id: 0xffff card_id: 0x0001
prod_id(1): "SCR243 PCMCIA" (0x2054e8de)
prod_id(2): "Smart Card Reader" (0xf5a90d5d)
prod_id(3): --- (---)
prod_id(4): --- (---)
# lsmod |grep pcmcia
pcmcia 43052 1 SCR24x
pcmcia_core 43412 4 SCR24x,pcmcia,yenta_socket,rsrc_nonstatic
使用讀卡機前可以用 pcsc_scan 指令來檢查,
不過我在使用上需先重插卡片再重啟pcscd才能正常使用,
算了,能用就好。最後就是上玉山的WebATM使用囉。
Posted in
技術,
Linux
|
Written on 2:31 上午 by Yu Lai
最近出差到泰國,真的被XP當到快發瘋了,
待出差回去後,把T60整個format掉裝起Ubuntu。
期間有一些安裝上的Note,就記錄在這裡囉。
(PS: 本篇會持續修改與增加內容。)
1. Track-Point的中鍵scroll功能
(Updated on 2010/07/05)
原本的方法在Ubuntu 10.04後就失效了QQ,
還好有人把該設定打包成套件直接使用。
先安裝gpointing-device-settings,
裝好執行後把Use wheel emulation打勾,
Button選2按Ok即可正常運作。
2. 把該死的dash拿掉
這個之前就有一篇在說明了,這裡再補記一下= =。
cd /bin
ln -sf bash sh
3. 使用root登入
這點很不建議,不過由於工作上的關係,常常需要compile到Linux Kernel,
加上又是NB,所以只好偷雞一下啦。
到/etc/gdm/gdm.conf內加入 AllowRoot=true 即可。
4. 安裝SCM SCR-243 PCMCIA Card Reader
這篇內容太多了,所以獨立出來。
Link: [技術]在Ubuntu安裝SCM SCR-243 PCMCIA Card Reader
5. 使用GPS配合Google Earth
Link: [技術] 在Ubuntu使用Holux M-1000C GPS配合Google Earth
6. 使用Wine存取Serial COM Port
Link: [技術] 在Wine中存取Serial COM Port
7. 取消udisks-daemon去polling光碟機
就算光碟機裡沒放光碟片,它還是偶爾會去讀取,一整個超怪。
# sudo hal-disable-polling --device /dev/sr0
8. 永久取消Pointer can be controlled using the keypad
修改/usr/share/X11/xkb/compat/complete檔,把augment "mousekeys"和augment "accessx(full)"取消掉。
如下:
// $XKeyboardConfig$
// $Xorg: complete,v 1.3 2000/08/17 19:54:34 cpqbld Exp $
default xkb_compatibility "complete" {
include "basic"
augment "iso9995"
// augment "mousekeys"
// augment "accessx(full)"
augment "misc"
augment "xfree86"
augment "level5"
};
9. 永久取消NumLock
使用gconf-editor,使用Ctrl+F,勾選"Search also in key names",找"numlock"。
然後Turn off "remember_numlock_state"和Turn off numlock "numlock_on"。
Posted in
技術,
GPS,
Linux,
PCMCIA,
SmartCard,
Thinkpad
|
Written on 6:56 下午 by Yu Lai
之前就裝過coLinux來玩過了,但後來公司配了workstation裝了Linux,
工作上的使用也都移到那台去run,於是就把coLinux給移掉了,沒辦法,佔空間啊。
最近要出差到國外做function verify,需要邊改邊測,總不能叫我還帶台
workstation出國吧,所以又把coLinux給裝起來了。不過隨著新版本coLinux,
安裝和設定上有些微的不同,以下就是這次安裝的步驟,就當做筆記吧。
1. 下載coLinux
首先,到coLinux的官網 http://www.colinux.org/ 下載最新的 coLinux,
點選download後它會幫你導向sourceforge,我抓到的版本為 0.7.4 版本。
這裡順便把coLinux幫我們包好的各大Linux Distribution的filesystem image
檔也抓下來,我使用的是 Debian-5.0r2-lenny.7z。
2. 安裝coLinux
抓完後執行解開,基本上照著點下一步就ok了。另外,TAP Driver記得安裝唷。
裝好後先別急著執行 coLinux,先把剛才的 Debian-5.0r2-lenny.7z 解開放在
coLinux的目錄下。
3. 網路設定-Windows
修改debian-lenny.conf的內容,把網路介面設成 eth0=tuntap。
(這一步看個人使用習慣,我是習慣透過tap配合NAT來使用。)
點選控制台->網路連線,把新增出來的網路介面名稱改為"TAP"方便示別。
接著點入原有的LAN的介面->內容->進階,把"允許其他網路使用著透過這台..."打勾,
開啟NAT的服務。
4. 網路設定-Debian
接著回到coLinux的目錄下執行debian-lenny.bat。
進到Debian的console後,用預設帳密 root / colinux 登入。先設定網路,
修改/etc/network/interfaces,把eth0的部份改為以下:
allow-hotplug eth0
iface eth0 inet static
address 192.168.0.100
netmask 255.255.255.0
gateway 192.168.0.1
修改/etc/resolv.conf,加入DNS:
nameserver 168.95.192.1
這裡補充一點,到/etc/modprobe.d/aliases把ipv6 Module給取消掉,
因為ipv6會影響到samba的運作,所以要修改一下:
alias net-pf-10 off
把以上這行取代掉原本的alias net-pf-10 ipv6即可。
5. 安裝Tools
再來就可以透過apt-get這個好用的tool把該裝的裝一裝了,
e.g. sshd, samba, gcc, subversion...etc。
這裡建議先裝前2個,這樣可以透過putty連進去,畫面操作上會比較順手。
6. 增加Partition
另外,由於我們的Partition是使用別人幫我們包好的filesystem image檔,
大小是固定的2gb。使用上多少會有所限制,所以這時可以透過以下方法新增
出額外的image檔來使用。
首先,在coLinux目錄下使用windows內建的指令來新增一空白的檔案:
c:\coLinux>fsutil file createnew Debian-pub.ext3.8gb 8589934592
這裡我建了一個8gb大小的檔案出來。
接著修改debian-lenny.conf的內容,把這個image檔mount進去,在conf檔內加入:
cobd1="Debian-pub.ext3.8gb"
改完後存檔,重新啟動coLinux,進到debian後,使用以下指令來建立ext3 filesystem:
debian# mkfs.ext3 /dev/cobd1
跑完後就可以mount啦,記得修改一下/etc/fstab把新的filesystem image自動mount起來:
/dev/cobd1 /pub ext3 errors=remount-ro 0 1
7. 總結
以上就是這次安裝的一些重要步驟,至於其他Debian設定上的細節就沒提到了。
有什麼問題再寫E-mail問我吧。
Posted in
技術,
File System,
Linux
|
Written on 4:01 下午 by Yu Lai
其實這篇應該是要接續上一篇寫的,因為用到的方法是和上一篇相同
的,但由於主題比較不太一樣,所以就分開來寫了。
在Linux中,一般要實做新的L3 protocol,大都是從kernel去下手,
效能較好,能存取的資源也比較多。但在開發embedded system下往
往有專案時間壓力以及軟體彈性的需求,去改kernel來達到這些要求
也就有點不太實際。所以我採用了在上一篇中使用的方法,也就是
Raw Socket與LPF(Linux Packet Filter)來完成一個L3 Protocol的
實做。
和Sniffer一樣的,我們使用了Raw Socket與LPF,比較不同的地方在
於LPF所使用的Filter。由於我們的protocol是定義成採用0x1219的
ether type,所以在配合tcpdump生成BPF code時用了以下的指令。
# tcpdump -dd -s 2048 ether proto 0x1219
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 1, 0x00001219 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }
以下是部份的實做的程式碼:
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/filter.h>
#include <linux/sockios.h>
void *mcpV2Handler(void *arg) {
int sock, n;
int rr;
U8 buf[2048];
U8 tmp[8], tmpSlot;
U8 lastBegMac[6];
U32 lastBegTime = 0;
U32 * pGroupKey;
tMcpFrame *frame;
tMcpPacket *packet;
tMcpCardInfo *cardInfo;
pthread_t mcpV2Sender_tid;
pthread_t mcpV2TxRx_tid;
struct sock_fprog filter;
/* Using tcpdump to generate BPF code */
/*
# tcpdump -d -s 2048 ether proto 0x1219
(000) ldh [12]
(001) jeq #0x1219 jt 2 jf 3
(002) ret #2048
(003) ret #0
*/
struct sock_filter bpf_code[]= {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 1, 0x00001219 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }
};
filter.len = sizeof(bpf_code)/sizeof(bpf_code[0]);
filter.filter = bpf_code;
/* set detached thread */
pthread_detach(pthread_self());
if ((sock=socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL)))<0) {
perror("socket");
exit(1);
}
/* Attach the bpf filter to the socket */
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))<0){
perror("setsockopt");
close(sock);
exit(1);
}
/* ----------- Start implement ----------- */
while(1) {
n = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
if(n < 22) { /* 6+6+2+2+4+2+N */
printf("invalid packet\n");
continue;
}
frame = (tMcpFrame *)buf;
if(memcmp(frame->srcAddr, myMac, 6) == 0)
continue;
MCP_LOG("Dump: %02x%02x%02x%02x%02x%02x|"
"%02x%02x%02x%02x%02x%02x|"
"%04x|%04x|%08x|%04x|"
"%02x %02x %02x %02x %02x %02x %02x %02x %02x",
frame->dstAddr[0], frame->dstAddr[1], frame->dstAddr[2],
frame->dstAddr[3], frame->dstAddr[4], frame->dstAddr[5],
frame->srcAddr[0], frame->srcAddr[1], frame->srcAddr[2],
frame->srcAddr[3], frame->srcAddr[4], frame->srcAddr[5],
ntohs(frame->etherType),
ntohs(frame->mcpProtoType),
ntohl(frame->groupKey),
ntohs(frame->dataLength),
frame->data[0], frame->data[1], frame->data[2], frame->data[3],
frame->data[4], frame->data[5], frame->data[6], frame->data[7], frame->data[8]);
if(ntohs(frame->mcpProtoType) == 1 && ntohl(frame->groupKey) == myGroupKey) {
/* blah blah */
/* blah blah */
/* blah blah */
}
}
close(sock);
}
Posted in
技術,
C,
Linux,
Network
|
Written on 1:39 下午 by Yu Lai
在這裡先感謝一下黃仁竑老師,因為這篇其實這是之前唸研究所時,
上課所要交的作業。沒想到最近在工作上也用到了,呵呵。
雖然在Linux下有許多好用的Sniffer工具,如: tcpdump 或 libpcap等。
但若了解如何自己實作Sniffer,對於實作網路相關的protocol會有更深的了解。
在實作sniffer之前,在Linux下有幾個東西我們要先了解。
首先是raw socket,透過raw socket,可以讓我們從Layer 2(Ethernet)
的資料開始解讀,而不是已經被核心處理過的tcp/udp payload。
sock=socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
接著是LPF(Linux Packet Filter),在Linux的kernel中,有個LPF的機制
可以預先設定過濾socket讀取到的內容。當然這個在實作sniffer不是必要
的,我們大可在讀取資料後自行filter掉非必要的data。但透過LPF,可以
讓我們專心在實作資料的呈現上。
而LPF的使用,我們可以使用一種pseudo-machine code language叫作BPF。
它是一種用來描述filter的語言,我們可以透過tcpdump這支好用的工具來
產生bpf的sample code。使用方法就是使用tcpdump -d 和
tcpdump -dd 來生出C使用的code。另外,tcpdump所生成的
sample code預設只會抓取96個字元,所以要再加上-s參數來指定抓取的數量。
tcpdump -d -s 2048 tcp and host 140.123.230.166
(000) ldh [12]
(001) jeq #0x86dd jt 10 jf 2
(002) jeq #0x800 jt 3 jf 10
(003) ldb [23]
(004) jeq #0x6 jt 5 jf 10
(005) ld [26]
(006) jeq #0x8c7be6a6 jt 9 jf 7
(007) ld [30]
(008) jeq #0x8c7be6a6 jt 9 jf 10
(009) ret #2048
(010) ret #0
tcpdump -dd -s 2048 tcp and host 140.123.230.166
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 8, 0, 0x000086dd },
{ 0x15, 0, 7, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 5, 0x00000006 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 2, 0, 0x8c7be6a6 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 0, 1, 0x8c7be6a6 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }
把Filter設到socket上。
struct sock_filter BPF_code[]= {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 8, 0, 0x000086dd },
{ 0x15, 0, 7, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 5, 0x00000006 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 2, 0, 0x8c7be6a6 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 0, 1, 0x8c7be6a6 },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 }
};
struct sock_fprog Filter;
Filter.len = 11;
Filter.filter = BPF_code;
setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter))
最後是把網卡的promiscuos mode打開,網卡一般會比對dst mac和自己的
Mac Address,若不相同或不是broadcast的封包會被drop掉不處理。
若要實作sniffer,這個mode一定要打開,才能監聽到別人的封包。
strncpy(ethreq.ifr_name,"eth0",IFNAMSIZ);
ioctl(sock,SIOCGIFFLAGS,ðreq);
ethreq.ifr_flags|=IFF_PROMISC;
ioctl(sock,SIOCSIFFLAGS,ðreq);
以下是完整的sample code,不過年代久遠,也沒時間compile測試,
如有錯誤不能compile,請見諒。XD
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h>
int main(int argc, char **argv) {
int sock, sock_server, sock_client, n, i;
char buffer[2048];
unsigned char *iphead, *ethhead, *tcphead;
int addr_len;
struct sockaddr_in sa_cli;
struct ifreq ethreq;
FILE* fPtr;
struct sock_filter BPF_code[]= {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 8, 0, 0x000086dd },
{ 0x15, 0, 7, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 5, 0x00000006 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 2, 0, 0x8c7be6a6 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 0, 1, 0x8c7be6a6 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }
};
struct sock_fprog Filter;
Filter.len = 11;
Filter.filter = BPF_code;
if ((sock=socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)))<0) {
perror("socket");
exit(1);
}
/* Set the network card in promiscuos mode */
strncpy(ethreq.ifr_name,"eth0",IFNAMSIZ);
if (ioctl(sock,SIOCGIFFLAGS,ðreq)==-1) {
perror("ioctl (SIOCGIFCONF) 1");
close(sock);
exit(1);
}
ethreq.ifr_flags|=IFF_PROMISC;
if (ioctl(sock,SIOCSIFFLAGS,ðreq)==-1) {
perror("ioctl (SIOCGIFCONF) 2");
close(sock);
exit(1);
}
/* Attach the filter to the socket */
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter))<0){
int temp=sizeof(Filter);
printf( "%d" , temp);
perror("setsockopt");
close(sock);
exit(1);
}
/* Open the result file. */
if ((fPtr = fopen("dump.txt", "w")) == NULL) {
perror("fopen");
close(sock);
exit(1);
}
while (1) {
n = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
printf("%d bytes read\n",n);
/* Check to see if the packet contains at least
* complete Ethernet (14), IP (20) and TCP/UDP
* (8) headers.
*/
if (n<42) {
perror("recvfrom():");
printf("Incomplete packet (errno is %d)\n", errno);
close(sock);
exit(0);
}
ethhead = buffer;
printf("Source MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
ethhead[0], ethhead[1], ethhead[2], ethhead[3], ethhead[4], ethhead[5]);
printf("Destination MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
ethhead[6], ethhead[7], ethhead[8], ethhead[9], ethhead[10], ethhead[11]);
iphead = buffer+14; /* Skip Ethernet header */
if (*iphead==0x45) { /* Double check for IPv4 and no options present */
printf("Source host %d.%d.%d.%d\n",
iphead[12], iphead[13], iphead[14], iphead[15]);
printf("Dest host %d.%d.%d.%d\n",
iphead[16], iphead[17], iphead[18], iphead[19]);
printf("Source,Dest ports %d,%d\n",
(iphead[20]<<8)+iphead[21], (iphead[22]<<8)+iphead[23]);
printf("Layer-4 protocol %d\n",
iphead[9]);
}
tcphead = iphead+20;
if (iphead[9] == 0x06) {
printf("TCP Sequence Number: %x%x%x%x\n",
tcphead[4], tcphead[5], tcphead[6], tcphead[7]);
printf("TCP Acknowledgement Number: %x%x%x%x\n",
tcphead[8], tcphead[9], tcphead[10], tcphead[11]);
printf("TCP Header Length: %d\n",
tcphead[12]>>4);
printf("TCP Control Bits: %02x (UAPRSF)\n",
tcphead[13]);
printf("TCP Window Size: %d\n",
(tcphead[14]<<8)+tcphead[15]);
for(i=4*(tcphead[12]>>4);i<n-14-20;i++) {
printf("%c", tcphead[i]);
}
printf("\n");
}
}
}
Ref:
http://www.linuxjournal.com/article/4659
Posted in
技術,
C,
Linux,
Network
|
Written on 10:36 上午 by Yu Lai
其實之前就有用到Timer,只是最近又再一次用到,所以把相關的部份整理一下。
在Linux下實做定時器有兩種方法,分別是alarm()和setitimer(),以下分別介紹:
1. alarm()
alarm()可以用來設定信號SIGALRM在指定的秒數後傳到目前的process。
使用起來比起setitimer較為簡單,但由於使用的單位是秒數,
所以如果不要求很精確的話,用alarm()配合signal()就夠了。
unsigned int alarm(unsigned int seconds)
alarm()用來設置信號SIGALRM在經過參數seconds指定的秒數後傳送給目前的process。
如果參數seconds為0,則之前設置的鬧鐘會被取消,並將剩下的時間返回,
如果之前未設鬧鐘則返回0。
void sigalrm_fn(int sig) {
printf("alarm!\n");
alarm(2);
return;
}
int main(void) {
signal(SIGALRM, sigalrm_fn);
alarm(1);
while(1) pause();
}
2. setitimer()
setitimer()比alarm功能強大,支持3種類型的Timer:
ITIMER_REAL : 以系統真實的時間來計算,它送出SIGALRM信號。
ITIMER_VIRTUAL : 以Process在User-Mode下花費的時間來計算,它送出SIGVTALRM信號。
ITIMER_PROF : 以Process在User-Mode下和Kernel-Mode下所費的時間來計算,它送出SIGPROF信號。
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
setitimer()第一個參數which指定定時器類型(上面三種之一);
第二個參數是struct itimerval的一個instance;第三個參數可不做處理。
setitimer()調用成功返回0,否則返回-1。
struct itimerval {
struct timeval it_interval; /* timer interval */
struct timeval it_value; /* current value */
};
itimerval結構中的it_value是減少的時間,當這個值為0的時候就發出相應的信號。
然後再將it_value設置為it_interval值。也就是說如果itimerval.it_interval不為0,
則該定時器將持續有效(每隔一段時間就會發送一個信號)。
下面是關於setitimer的一個簡單示範,在該例子中,
每隔一秒發出一個SIGALRM,每隔0.5秒發出一個SIGVTALRM信號:
int sec;
void sigroutine(int signo) {
switch (signo){
case SIGALRM:
printf("Catch a signal -- SIGALRM \n");
signal(SIGALRM, sigroutine);
break;
case SIGVTALRM:
printf("Catch a signal -- SIGVTALRM \n");
signal(SIGVTALRM, sigroutine);
break;
}
return;
}
int main() {
struct itimerval value, ovalue, value2;
sec = 5;
printf("process id is %d\n", getpid());
signal(SIGALRM, sigroutine);
signal(SIGVTALRM, sigroutine);
value.it_value.tv_sec = 1;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 1;
value.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &value, &ovalue);
value2.it_value.tv_sec = 0;
value2.it_value.tv_usec = 500000;
value2.it_interval.tv_sec = 0;
value2.it_interval.tv_usec = 500000;
setitimer(ITIMER_VIRTUAL, &value2, &ovalue);
for(;;) ;
}
PS:
Linux信號機制基本上是從Unix系統中繼承過來的。
早期Unix系統中的信號機制比較簡單和原始,後來在實踐中暴露出一些問題,
因此,把那些建立在早期機制上的信號叫做"不可靠信號",
信號值小於SIGRTMIN(SIGRTMIN=32,SIGRTMAX=63)的信號都是不可靠信號。
這就是"不可靠信號"的來源。它的主要問題是:Process每次處理信號後,
就將對信號的響應設置為Default動作。在某些情況下,將導致對信號的錯誤處理;
因此,User如果不希望這樣的操作,那麼就要在信號處理函數結尾再一次使用signal(),重新安裝該信號。
Posted in
C,
Linux,
Signal
|
Written on 8:50 上午 by Yu Lai
一般在C中,我們可以使用opendir()與readdir()來列出目錄下所有的檔案。
以下是範例程式:
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
main() {
DIR * dir;
struct dirent * ptr;
int i;
dir =opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL) {
printf(“d_name: %s\n”,ptr->d_name);
}
closedir(dir);
}
配合struct dirent,定義如下:
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256];
};
d_ino 此目錄進入點的inode
d_off 目錄文件開頭至此目錄進入點的位移
d_reclen d_name的長度,不包含NULL字符
d_type d_name所指的檔案類型
d_name 檔名
其中unsigned cahr d_type;可以來判斷是子目錄或是一般的檔案。
但不知是我使用的uClibC的問題,沒實作到還怎樣,使用上一直有問題。
後來還是找到解決方法,方法有2種,分別如下:
1. 再使用一次readdir()來判斷回傳值,若回傳為NULL,即為檔案。
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
main() {
DIR * dir;
DIR * dir2;
struct dirent * ptr;
int i;
dir =opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL) {
char pathname[100];
sprintf(pathname,"/etc/rc.d/%s", ptr->d_name);
if((dir2 = opendir(pathname))==NULL) {
printf("%s: file\n", ptr->d_name);
} else {
printf("%s: directory\n", ptr->d_name);
closedir(dir2);
}
}
closedir(dir);
}
2. 使用int stat(const char *file_name, struct stat *buf),
在struct stat其中的 st_mode 可以用來判斷是哪種檔案(也就是上面 d_type的 功用)。
為了方便,POSIX另外有定義幾個MACRO:
S_ISLNK(st_mode) : 是symbolic link
S_ISREG(st_mode) 一般檔案(regular file)
S_ISDIR(st_mode) 目錄(directory)
S_ISCHR(st_mode) 字元設備檔(char device)
S_ISBLK(st_mode) 區塊設備檔(block device)
S_ISSOCK(st_mode) local-domain socket
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
main() {
DIR * dir;
struct dirent * ptr;
int i;
dir =opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL) {
char pathname[100];
struct stat buf;
sprintf(pathname,"/etc/rc.d/%s", ptr->d_name);
stat(pathname, &buf);
if(S_ISREG(buf.st_mode))
printf("%s: file\n", ptr->d_name);
else
printf("%s: directory\n", ptr->d_name);
}
closedir(dir);
}
Posted in
技術,
C,
File System,
Linux
|