Thursday, January 28, 2010

linux-0.11-RW

int sys_read(unsigned int fd,char * buf,int count)
{
struct file * file;
struct m_inode * inode;

if (fd>=NR_OPEN || count<0 file="current-">filp[fd]))
return -EINVAL;
if (!count)
return 0;
verify_area(buf,count);
inode = file->f_inode;
if (inode->i_pipe)
return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; /* pipe mode hadn't been added in stat.h*/
if (S_ISCHR(inode->i_mode))
return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
if (S_ISBLK(inode->i_mode))
return block_read(inode->i_zone[0],&file->f_pos,buf,count); /*
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
if (count+file->f_pos > inode->i_size)
count = inode->i_size - file->f_pos; /*truncate to the boundary*/
if (count<=0)
return 0;
return file_read(inode,file,buf,count);
}
printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}

1.what does inode->i_zone[0] contain ?
it stores character/block's logical device number as oppose of logical block number in regular file.

2.file points to a global file entry, if the offset was modified in this process, will other processes be affected ?

3. we can treat directory as regular file.

To summarize this function, in linux there're basic 4 types of readable things: 1.pipe 2.character device 3.block device 4.directory and regular file.

pipe resides on memory area, it normally has two ends. one for reading, one for writing.

4. some perpheral apparatus have its own buffer, which could facilitate the data transmission. how to fetch data out of the buffer ?

5.why the code verifies the buf ?
buf value assigns to the function is the logical address. get_base(current->ldt[2]); translates logical address to virtual address.

void verify_area(void * addr,int size)
{
unsigned long start;

start = (unsigned long) addr;
size += start & 0xfff; /* fully align to block boundary*/
start &= 0xfffff000; /* locate which block the addr is belonging to */
start += get_base(current->ldt[2]);
while (size>0) {
size -= 4096;
write_verify(start);
start += 4096;
}
}

int read_pipe(struct m_inode * inode, char * buf, int count)
{
int chars, size, read = 0;
while (count>0) {
while (!(size=PIPE_SIZE(*inode))) {
wake_up(&inode->i_wait);
if (inode->i_count != 2) /* are there any writers? */
return read;
sleep_on(&inode->i_wait);
}
chars = PAGE_SIZE-PIPE_TAIL(*inode);
if (chars > count)
chars = count;
if (chars > size)
chars = size;
count -= chars;
read += chars;
size = PIPE_TAIL(*inode);
PIPE_TAIL(*inode) += chars;
PIPE_TAIL(*inode) &= (PAGE_SIZE-1);
while (chars-->0)
put_fs_byte(((char *)inode->i_size)[size++],buf++);
}
wake_up(&inode->i_wait);
return read;
}

1.what if count is greater than chars ?
in such case, the reading action will repeat.

2.what i_zone[0] and i_zone[1] represent in pipe inode ? an memory address or an integer ?
Theoretically speaking, i_zone[0/1] only could contain integre, which is used to index in array.

PIPE_TAIL(*inode) &= (PAGE_SIZE-1); if reading or writing operation exceeds the upper side boundary, the pointer will wrap around to the beginning of the pipe buffer.
this piece code is much like

while (PIPE_TAIL(*inode) > ( PAGE_SIZE-1 ) )
PIPE_TAIL(*inode) = PIPE_TAIL(*inode) - (PAGE_SIZE-1 ) ;

size : the available amount
chars : represent the distance of tail or head to the upper side of pipe buffer. Note, it doesn't stand for the amount of pipe data.

Tuesday, January 26, 2010

SIP Lab Environment


This is a basic Lab environment, which i'm going to build up in the following two months.

Saturday, March 28, 2009

linux-0.11-mm-3

void do_wp_page(unsigned long error_code,unsigned long address)

{

#if

/* we cannot do this yet: the estdio library writes to code space */

/* stupid, stupid. I really want the libc.a from GNU */

if (CODE_SPACE(address))

do_exit(SIGSEGV);

#endif

un_wp_page((unsigned long *)

(((address>>10) & 0xffc) + (0xfffff000 &

*((unsigned long *) ((address>>20) &0xffc)))));


}


void un_wp_page(unsigned long * table_entry) // *table_entry is the entry in page table

{

unsigned long old_page,new_page;


old_page = 0xfffff000 & *table_entry; /*old_page is refer to the physical address */

/*MAP_NR-->>calculate the INDEX and guarantee that this page is only being referenced by one */

if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {

*table_entry |= 2; // set R/W bit , clear exception protection.

invalidate();

return;

}

/*if there're two or more references, just decrease one and copy the orginal content to new area*/

if (!(new_page=get_free_page()))

oom();

if (old_page >= LOW_MEM)

mem_map[MAP_NR(old_page)]--;

*table_entry = new_page | 7;

invalidate();

copy_page(old_page,new_page);

/*

#define copy_page(from,to) \

__asm__("cld ; rep ; movsl" movsl: move from %esi to %edi

:

:"S" (from),"D" (to),"c" (1024) %esi %edi

:"cx","di","si")


*/


}

int copy_page_tables(unsigned long from,unsigned long to,long size)

{

unsigned long * from_page_table;

unsigned long * to_page_table;

unsigned long this_page;

unsigned long * from_dir, * to_dir;

unsigned long nr;


if ((from&0x3fffff) || (to&0x3fffff))

panic("copy_page_tables called with wrong alignment");

from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */

to_dir = (unsigned long *) ((to>>20) & 0xffc);

size = ((unsigned) (size+0x3fffff)) >> 22;

for( ; size-->0 ; from_dir++,to_dir++) {

if (1 & *to_dir)

panic("copy_page_tables: already exist");

if (!(1 & *from_dir))

continue; /*source doesn't exist, just skip it*/

from_page_table = (unsigned long *) (0xfffff000 & *from_dir);/* get the pointer of page table*/

/*allocate physical memory with a page size to destination table*/

if (!(to_page_table = (unsigned long *) get_free_page()))

return -1; /* Out of memory, see freeing */

*to_dir = ((unsigned long) to_page_table) | 7; /*record the preceding page table to directory table*/

nr = (from==0)?0xA0:1024;

for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {

this_page = *from_page_table;

if (!(1 & this_page))

continue;

this_page &= ~2; /*this_page & 0xfffff000 ==>> the begining of page in physical memory*/

*to_page_table = this_page;

if (this_page > LOW_MEM) {

*from_page_table = this_page;

this_page -= LOW_MEM;

this_page >>= 12;

mem_map[this_page]++; /*increase the count of reference.*/

}

}

}

invalidate();

return 0;

}

Friday, March 27, 2009

linux-0.11-mm-2

unsigned long put_page(unsigned long page,unsigned long address)
{
unsigned long tmp, *page_table;

/* NOTE !!! This uses the fact that _pg_dir=0 */

if (page <>= HIGH_MEMORY)
printk("Trying to put page %p at %p\n",page,address);
if (mem_map[(page-LOW_MEM)>>12] != 1) //this element should be marked as used before invoking this function
printk("mem_map disagrees with %p at %p\n",page,address);
page_table = (unsigned long *) ((address>>20) & 0xffc);
/*address>>20: address>>22 locate the INDEX in directory table.the pointer of each entry equals to INDEX x 4, because each entry occupies 4 bytes. finally, simplify the expression to "address>>20", least but not last, the last 2 bits must be set to 0.*/
if ((*page_table)&1)
page_table = (unsigned long *) (0xfffff000 & *page_table);// *page_table is page table entry.
else {
if (!(tmp=get_free_page())) //get the physical address of a new page from main memory.
return 0;
*page_table = tmp|7;
page_table = (unsigned long *) tmp;
}
page_table[(address>>12) & 0x3ff] = page | 7; /*save the pointer pointing to the begining of page to page table. 7 means:P=1.
R/W=1 read-and-write . U/S = 1 for application procedures and data. */
/* no need for invalidate */
return page;
}

linux-0.11-mm-1

unsigned long get_free_page(void)
{
register unsigned long __res asm("ax");// AS(16bit) consists of AH(8bit) and AL (8bit)
// repne: %cx is decremented by 1 each cycle.
__asm__("std ; repne ; scasb\n\t" //"scasb"compare 0(%1) with %edi:end of mem_map(%4) repne: repeat if ZF=0.doesn't find empty page
"jne 1f\n\t" // JUMP IF ZF(zero flag in EFLAGS) =0. when reach here, ZF=1.(No more page ZF=0)
"movb $1,1(%%edi)\n\t"//Found empty page.Mark used.after executed "scasb",pointed to next position.so need to add 1 before set
"sall $12,%%ecx\n\t" // multiple %ecs 12 times. %edi is the destination of string operation.4MbX (target page)=relative ADD.
"addl %2,%%ecx\n\t" //%2 LOW_MEM. LOW_MEM + relative address = absolute address
"movl %%ecx,%%edx\n\t" // save to %edx
"movl $1024,%%ecx\n\t" // set counts
"leal 4092(%%edx),%%edi\n\t" // move to the end point of target page.
"rep ; stosl\n\t" // move %eax // copy AL = 0 to %edi and %edi decrement. initialize this page.
"movl %%edx,%%eax\n" // %edx the begining of this page. send to output.
"1:"
:"=a" (__res) // %eax
:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), // "c"--> %ecx "i"-->> a constant value
"D" (mem_map+PAGING_PAGES-1) // D -->>> %edi
:"di","cx","dx");
return __res;
}

Sunday, November 23, 2008

[FW] cscope in linux kernel


Using Cscope on large projects (example: the Linux kernel)Cscope can be a particularly useful tool if you need to wade into a large code base. You can save yourself a lot of time by being able to do fast, targeted searches rather than randomly grepping through the source files by hand (especially since grep starts to take a while with a truly large code base).
In this tutorial you'll learn how to set up Cscope with a large project. We'll use as our example the Linux kernel source code, but the basic steps are the same for any other large project, including C++ or Java projects.
Get the source. First get the source code. You can download the Linux kernel source from http://www.kernel.org/. For the rest of this tutorial, I'll assume you've downloaded Linux 2.4.18 and installed it into /home/jru/linux-2.4.18.
Note: Make sure you've got enough disk space: the kernel tarball alone is 30 MB, it expands into 150 MB of source code, and the Cscope database we'll generate will gobble up another 20-100+ MB (depending on how much of the kernel code you decide to include in the database). You can put the Cscope database on a different disk partition than the source code if you need to.
Figure out where you want to put your Cscope database files. I'll assume you'll use /home/jru/cscope as the directory to store your database and associated files.
Generate cscope.files with a list of files to be scanned. For some projects, you may want to include every C source file in the project's directories in your Cscope database. In that case you can skip this step, and just use 'cscope -R' in the project's top-level directory to build your Cscope database. But if there's some code that you wish to exclude, and/or your project contains C++ or Java source code (by default Cscope only parses files with the .c, .h, .y, or .l extensions), you'll need to generate a file called cscope.files, which should contain the name of all files that you wish to have Cscope scan (one file name per line).
You'll probably want to use absolute paths (at least if you're planning to use the Cscope database within an editor), so that you can use the database from directories other than the one you create. The commands I show will first cd to root, so that find prints out absolute paths.
For many projects, your find command may be as as simple as cd /
find /my/project/dir -name '*.java' >/my/cscope/dir/cscope.files
For the Linux kernel, it's a little trickier, since we want to exclude all the code in the docs and scripts directories, plus all of the architecture and assembly code for all chips except for the beloved Intel x86 (which I'm guessing is the architecture you're interested in). Additionally, I'm excluding all kernel driver code in this example (they more than double the amount of code to be parsed, which bloats the Cscope database, and they contain many duplicate definitions, which often makes searching harder. If you are interested in the driver code, omit the relevant line below, or modify it to print out only the driver files you're interested in): LNX=/home/jru/linux-2.4.18
cd /
find $LNX \
-path "$LNX/arch/*" ! -path "$LNX/arch/i386*" -prune -o \
-path "$LNX/include/asm-*" ! -path "$LNX/include/asm-i386*" -prune -o \
-path "$LNX/tmp*" -prune -o \
-path "$LNX/Documentation*" -prune -o \
-path "$LNX/scripts*" -prune -o \
-path "$LNX/drivers*" -prune -o \
-name "*.[chxsS]" -print >/home/jru/cscope/cscope.files

While find commands can be a little tricky to write, for large projects they are much easier than editing a list of files manually, and you can also cut and paste a solution from someone else.
Generate the Cscope database. Now it's time to generate the Cscope database: cd /home/jru/cscope # the directory with 'cscope.files'
cscope -b -q -k
The -b flag tells Cscope to just build the database, and not launch the Cscope GUI. The -q causes an additional, 'inverted index' file to be created, which makes searches run much faster for large databases. Finally, -k sets Cscope's 'kernel' mode--it will not look in /usr/include for any header files that are #included in your source files (this is mainly useful when you are using Cscope with operating system and/or C library source code, as we are here).
On my 900 MHz Pentium III system (with a standard IDE disk), parsing this subset of the Linux source takes only 12 seconds, and results in 3 files (cscope.out, cscope.in.out, and cscope.po.out) that take up a total of 25 megabytes.
Using the database. If you like to use vim or emacs/xemacs, I recommend that you learn how to run Cscope within one of these editors, which will allow you to run searches easily within your editor. We have a tutorial for Vim, and emacs users will of course be clever enough to figure everything out from the helpful comments in the cscope/contrib/xcscope/ directory of the Cscope distribution.
Otherwise, you can use the standalone Cscope curses-based GUI, which lets you run searches, then launch your favorite editor (i.e., whatever $EDITOR is set to in your environment, or 'vi' by default) to open on the exact line of the search result.
If you use the standalone Cscope browser, make sure to invoke it via cscope -d
This tells Cscope not to regenerate the database. Otherwise you'll have to wait while Cscope checks for modified files, which can take a while for large projects, even when no files have changed. If you accidentally run 'cscope', without any flags, you will also cause the database to be recreated from scratch without the fast index or kernel modes being used, so you'll probably need to rerun your original cscope command above to correctly recreate the database.
Regenerating the database when the source code changes.
If there are new files in your project, rerun your 'find' command to update cscope.files if you're using it.
Then simply invoke cscope the same way (and in the same directory) as you did to generate the database initially (i.e., cscope -b -q -k).

Tutorial by Jason Duell
Back to the Cscope home page

how to use linux symbol ?

exporting the symbols which are defined in Kernel, so that other program would use it freely.
for instance. TEST_SYMBOL is the one.
first : using macro EXPORT_SYMBOL(TEST_SYMBOL) in xxxx_ksyms.c file, which is architecture-dependant. locate it by using : slocate ksyms
second: reference it in your source file extern TEST_SYMBOL

emacs copy method: c- , M-W , C-Y

Tuesday, September 9, 2008

转:L2TP

L2TP(Layer Two Tunneling Protocol,第二层通道协议)是VPDN(虚拟专用拨号网络)技术的一种,专门用来进行第二层数据的通道传送,即将第二层数据单元,如点到点协议(PPP)数据单元,封装在IP或UDP载荷内,以顺利通过包交换网络(如Internet),抵达目的地。
L2TP提供了一种远程接入访问控制的手段,其典型的应用场景是:某公司员工通过PPP拨入公司本地的网络访问服务器(NAS),以此接入公司内部网络,获取IP地址并访问相应权限的网络资源;该员工出差到外地,此时他想如同在公司本地一样以内网IP地址接入内部网络,操作相应网络资源,他的做法是向当地ISP申请L2TP服务,首先拨入当地ISP,请求ISP与公司NAS建立L2TP会话,并协商建立L2TP隧道,然后ISP将他发送的PPP数据通道化处理,通过L2TP隧道传送到公司NAS,NAS就从中取出PPP数据进行相应的处理,如此该员工就如同在公司本地那样通过NAS接入公司内网。
从上述应用场景可以看出L2TP隧道是在ISP和NAS之间建立的,此时ISP就是L2TP访问集中器(LAC),NAS也就是L2TP网络服务器(LNS)。LAC支持客户端的L2TP,用于发起呼叫,接收呼叫和建立隧道,LNS则是所有隧道的终点。在传统的PPP连接中,用户拨号连接的终点是LAC,L2TP使得PPP协议的终点延伸到LNS。
L2TP本质上是一种隧道传输协议,它使用两种类型的消息:控制消息和数据隧道消息。控制消息负责创建、维护及终止L2TP隧道,而数据隧道消息则负责用户数据的真正传输。L2TP支持标准的安全特性CHAP和PAP,可以进行用户身份认证。在安全性考虑上,L2TP仅定义了控制消息的加密传输方式,对传输中的数据并不加密。
IPsec(IP Security),顾名思义,是保障IP层安全的网络技术,它并不是指某一项具体的协议,而是指用于实现IP层安全的协议套件集合。IPsec实质上也是一种隧道传输技术,它将IP分组或IP上层载荷封装在IPsec报文内,并根据需要进行加密和完整性保护处理,以此保证数据在公共网络中传输过程的安全。
IPsec支持两种协议标准,鉴别首部(Authenticaion Header,AH)和封装安全有效载荷(Encapsulation Security Payload,ESP):
AH可证明数据的起源地(数据来源认证)、保障数据的完整性以及防止相同的数据包不断重播(抗重放攻击);
ESP能提供的安全服务则更多,除了上述AH所能提供的安全服务外,还能提供数据机密性,这样可以保证数据包在传输过程中不被非法识别;
AH与ESP提供的数据完整性服务的差别在于,AH验证的范围还包括数据包的外部IP头。
为正确实施IPsec封装及解封装IP数据包,必须建立IPsec隧道,也就是需要定义加密或鉴别算法、算法使用的密钥、密钥保持有效的生命期以及授权可用的数据访问策略等信息,这也被称为"安全联盟(Security Association,SA)"。
通常采用IKE(Internet Key Exchange,因特网密钥交换)协议来协商建立IPsec隧道。IKE协商实际上有两个阶段:
第一阶段协商,是在IPsec通信双方之间建立IKE的安全通道,即建立IKE SA,这个过程有两种模式,一种是常用的主模式(Main Mode),能提供身份保护服务,但需要较多的消息交互(多达六条消息),另一种是比较迅速的积极模式(Aggressive Mode),但协商能力较弱,也不能提供身份保护功能;
第二阶段协商是在IKE SA的保护下进行的,其目的是为特定的通信流协商IPsec安全通道,即建立IPsec SA。
由此可以看出IKE的主要作用是负责建立、维护和终止IPsec安全通道,通过其他的一些消息交换过程,可以帮助维持IPsec通道的可用性和安全性,服务于IPsec数据的安全传输。
这与L2TP控制消息帮助建立和维护L2TP数据传输通道的作用有异曲同工之妙。两者都可以提供通信双方之间的身份认证,并且都可以在提供完整性保护和机密性服务的环境下进行安全的有关参数协商和消息交互;同时还能根据各自的特点,提供一种保活(keepalive)机制来负责协调隧道双方的状态的同步,提高隧道的容错性和稳定性,所不同的是,IKE是充分利用IPsec通信流存在即对方活跃状态的证明的特点,以此减少保活报文通信量,这种方式也被称为"DPD(Dead Peer Detection,死亡对端探测)"。此外IKE的协商能力也远大于L2TP控制消息交互。
L2TP与IPsec的一个最大的不同在于它不对隧道传输中的数据进行加密,从而没法保证数据传输过程中的安全。因此这个时候,L2TP常和IPsec结合使用,先使用L2TP封装第二层数据,再使用IPsec封装对数据进行加密和提供完整性保护,由此保证通信数据安全传送到目的地。
L2TP由于封装的是第二层协议数据,因此可以认为是一种L2VPN(第二层VPN)技术。最新的L2TP协议草案(L2TP v3)表明,L2TP不仅可以封装PPP数据单元,还可以封装其他第二层协议数据,如Ethernet(以太网)、Frame Relay(帧中继)等。因此L2TP的作用已经扩展到将异地的局域网通过L2TP隧道跨越公共网络连接在一起,也就是实现异地局域网互联,这样可以将某些局域网技术如VLAN(虚拟局域网)应用到异地局域网之间,从而利用公共网络来模拟局域网。当然其数据传输过程中的安全性仍然依赖于IPsec来提供。同时由于对数据进行了层层封装,这样难免影响效率,导致性能不高。
IPsec封装的是IP层数据,或是IP上层协议载荷,因此可以认为是一种构建L3VPN(第三层VPN)的技术。其最大的特点是为数据传输过程提供了机密性、完整性保护和数据源验证,从而确保承载于公共网络的VPN的安全性和可靠性,同时由于添加的协议头并不多,且还可以利用硬件加密卡加速IPsec报文的处理,因而效率上得到了很大的提高;此外IKE协商过程能提供比较完备的用户身份认证,这就使得可以对IPsec用户访问实施有力控制,从而进一步保证了网络的安全。
因此就一般企业用户构建安全的VPN而言,应该使用IPsec技术,当然如果需要实现安全的VPDN,就应该采用L2TP+IPsec组合技术。

Friday, August 1, 2008

CISCO Presence Server (2)

When CUPC registers to CUPS , it sends 3 SIP packets.


A: subscribe to the contact-list
Method : SUBCRIBE
Event: presence


B: subscribe to the live presence of each user in the contact-list.
Method : SUBCRIBE
Event: presence

C: I have no idea what's function of this packet ? but CUPS just replied BAD EVENT.

Method : SUBCRIBE
Event: profileconfig ------------------------------????

CISCO Presence Server Note



THE Presence Support in CCM
BLF speed dial work as both speed dial and presence indicator .
Presence policy : 1. Subscribe calling search space. It determines how to route watcher's presence request ( a Subscribe request with event field set to presence ) . With Subscribe calling search space set to NONE , BLF speed dials and other presence service will not work.
2. presence group : it controls the destinations that watchers can see. It takes precedence over SUBSCRIBE Calling Search space.

Integration CCM and CUPS :
SIP :
1.CCM side : configure a SIP Trunk pointing to CUPS.
2.CUPS side: configure a presence gateway : ip_address_of_CCM:5070
this SIP connection between them handles all presence information exchange(??????????????????????)
CTI-QBE (Computer Telephony Integration Quick buffer Encoding):
this connection handles all CTI communication for user on CUPCS to control IP Phone on CCM.
1.CCM side : the user's primary extension must be enabled for CTI control
the user must belongs to CTI-enable group.
2.CUPS side: CTI server and profile are automatically created during database synchronization with CCM. CUPC CTI
communication occurs directly with CCM.

AXL/SOAP :
1.CCM side : no additional configuration is required.
2.CUPS side: set a user and password for the CCM AXL account in AXL configuration .

LDAP :
CCM retrieves USER information from LDAP directly.
when CUPC logins to CUPS and CCM's LDAP authentication is enabled , CUPS will directly go to LDAP for CUPC authentication .




Phone-association mode Configuration steps :
1.add IP Phone , bond with the user
2.configurate the user ( standard CCM end user , CIT enable user ) , primary number .
assign UPC and UPS capability on CCM.
3.Specify CTI gateway ( CTI Manager on CCM) (usually CTI Gateway has been automatically assigned in the installation )
4.CTI GW profile
5.SIP proxy profile (ensure the connection between Personal communicator and CUPS adopts TCP ) ????
6.Applicaiton profile ( optional , provide different services for users )


CUPC boot-up procedure
1.CUPC authenticates against CUPS by using SSL ( CUPS retrieve the user information from CCM5)
2.CUPC checks the TFTP address configured on CUPS and downloads the user preference from the TFTP server.
3.CUPC registers to CUPS via SIP and subscribers the buddy-list
4.CUPC registers its soft phone or Desktop phone to CCM , meanwhile , it connects to IMAP for VoiceMail via CUP.

Do NOT use Hostname in a environment without DNS Server deployed.